一、需求背景
之前介紹過我們項目的架構,由于歷史原因,架構演變成as<-->java<-->php這樣,java與as通過tcp長連接通信,java與php通過兩條http通道來通信(java與php各自有個http server,并各自作為對方的http client,java轉發as以前的post給php;php需要跨session推送或者廣播時變為http client向java的http server做post)。
這之前的架構是as的功能邏輯大部分直接與php進行http通信。
項目的目標是慢慢將php部分寫的糟糕的已有邏輯(例如幫派這種交互和廣播同步比較多的)改到java服務器上。項目人員配備跟不上,所以不能一下子全轉了。
如果用之前的兩條http通道來小步快跑式的移邏輯,就需要再封裝這兩個通道之間的通信,費時間還不一定好使,所以我們需要一個java直接調用php的技術。
goole了解后,最終決定使用PHP/Java Bridge。
二、PHP/Java Bridge
(一)示例
CallPhp.java
1 package me.sheppardy.study;
2
3 import java.io.ByteArrayOutputStream;
4 import java.io.FileReader;
5
6 import javax.script.ScriptEngine;
7 import javax.script.ScriptEngineManager;
8
9 /**
10 *
11 * PHP/Java Bridge, example
12 * @author sheppard(ysf1026@gmail.com) 2013-01-18
13 *
14 */
15 public class CallPhp
16 {
17
18 public static void main(String[] args) throws Exception
19 {
20 test(1104);
21 test(531);
22 test(1221);
23 test(110);
24 }
25
26 public static void test(int id) throws Exception
27 {
28 Response rep = new Response();
29 call(new Request(id), rep);
30 System.out.println("CallPhp.test, id=" + id + " message=" + rep.message);
31 }
32
33 public static void call(Request req, Response rep) throws Exception
34 {
35 ScriptEngineManager engineManager = new ScriptEngineManager();
36 ScriptEngine engine = engineManager.getEngineByName("php-invocable");
37
38 ByteArrayOutputStream log = new ByteArrayOutputStream();
39
40 try
41 {
42 engine.put("phpRootDir", "data/php");
43 engine.put("log", log);
44 engine.put("req", req);
45 engine.put("rep", rep);
46 FileReader reader = new FileReader("data/php/gate.php");
47 engine.eval(reader);
48 System.out.println("CallPhp.call phpLog=" + log.toString());
49 }
50 catch(Exception e)
51 {
52 System.out.println("CallPhp.call phpLog=" + log.toString());
53 throw e;
54 }
55 }
56 }
57
58 class Request
59 {
60 public Request(int id)
61 {
62 this.id = id;
63 }
64 public int id;
65 }
66
67 class Response
68 {
69 public String message;
70 }
java-bin/data/php/gate.php
1 <?php
2
3 /**
4 *
5 * 腳本統一入口
6 * @author sheppard(ysf1026@gmail.com) 2013-01-18
7 *
8 */
9
10 define('PHP_ROOT_DIR', java_context()->get('phpRootDir'));
11 $log = java_context()->get('log');
12 $log->write("\n\tjava give phpRootDir is " . PHP_ROOT_DIR);
13
14 require_once(PHP_ROOT_DIR . '/function.php');
15
16 $log->write(getDoomsday());
17
18 $rep = java_context()->get('rep');
19 $rep->message = handle(java_context()->get('req'), $log);
20
21 ?>
java-bin/data/php/function.php
1 <?php
2
3 /**
4 *
5 * 具體功能舉例
6 * @author sheppard(ysf1026@gmail.com) 2013-01-18
7 *
8 */
9
10 function getDoomsday()
11 {
12 return "\n\tdoomsday is 20121221";
13 }
14
15 function handle($req, $log)
16 {
17 $id = $req->id;
18 $log->write("\n\tfunction.php handle id=$id");
19 if('1104' == $id)
20 return 'guess?';
21 else if('531' == $id)
22 return 'score';
23 else if('1221' == $id)
24 return 'maybe doomsday';
25 else
26 return '404 not found';
27 }
28
29 ?>
output
1 CallPhp.call phpLog=
2 java give phpRootDir is data/php
3 doomsday is 20121221
4 function.php handle id=1104
5 CallPhp.test, id=1104 message=guess?
6 CallPhp.call phpLog=
7 java give phpRootDir is data/php
8 doomsday is 20121221
9 function.php handle id=531
10 CallPhp.test, id=531 message=score
11 CallPhp.call phpLog=
12 java give phpRootDir is data/php
13 doomsday is 20121221
14 function.php handle id=1221
15 CallPhp.test, id=1221 message=maybe doomsday
16 CallPhp.call phpLog=
17 java give phpRootDir is data/php
18 doomsday is 20121221
19 function.php handle id=110
20 CallPhp.test, id=110 message=404 not found
(二)注意事項
1. 由于是java調用的php,所以php里當前工作路徑變成了java的。
2. FileReader加載*.php文件之后ScriptEngine.evel(FileReader)的耗時大概為230+ms,StringReader時為180+ms,速度都不咋滴,但是這不是我們項目急著考慮的問題,之前的http方式也好不到哪去,優化留到以后再說。
3. php的解釋器運行路徑配置:-Dphp.java.bridge.php_exec=。
三、相關資料
1. 官網:http://php-java-bridge.sourceforge.net/pjb/
2. 符合java調腳本標準的調php示例:http://php-java-bridge.sourceforge.net/pjb/examples/source.php?source=PhpThreads.java
ps:2013年1月18日我在CU的博客