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