一、需求背景
之前介绍过我们项目的架构,由于历史原因,架构演变成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的博客