PHP/Java Bridge 的使用
需求背景
之前介绍过我们项目的架构,由于历史原因,架构演变成这样:1
ActionScript <--> 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 的技术。 Google 了解后,最终决定试试 PHP/Java Bridge。
PHP/Java Bridge
示例
CallPhp.java:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56package me.clawz.study;
import java.io.ByteArrayOutputStream;
import java.io.FileReader;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
public class CallPhp {
public static void main(String[] args) throws Exception {
test(1104);
test(531);
test(1221);
test(110);
}
public static void test(int id) throws Exception {
Response rep = new Response();
call(new Request(id), rep);
System.out.println("CallPhp.test, id=" + id + " message=" + rep.message);
}
public static void call(Request req, Response rep) throwsException {
ScriptEngineManager engineManager = new ScriptEngineManager();
ScriptEngine engine = engineManager.getEngineByName("php-invocable");
ByteArrayOutputStream log = new ByteArrayOutputStream();
try {
engine.put("phpRootDir", "data/php");
engine.put("log", log);
engine.put("req", req);
engine.put("rep", rep);
FileReader reader = new FileReader("data/php/gate.php");
engine.eval(reader);
System.out.println("CallPhp.call phpLog=" + log.toString());
}
catch(Exception e) {
System.out.println("CallPhp.call phpLog=" + log.toString());
throw e;
}
}
}
class Request
{
public Request(int id) {
this.id = id;
}
public int id;
}
class Response {
public String message;
}脚本统一入口 java-bin/data/php/gate.php:
1
2
3
4
5
6
7
8
9
10
11
12
define('PHP_ROOT_DIR', java_context()->get('phpRootDir'));
$log = java_context()->get('log');
$log->write("\n\tjava give phpRootDir is " . PHP_ROOT_DIR);
require_once(PHP_ROOT_DIR . '/function.php');
$log->write(getDoomsday());
$rep = java_context()->get('rep');
$rep->message = handle(java_context()->get('req'), $log);具体功能举例 java-bin/data/php/function.php:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
function getDoomsday() {
return "\n\tdoomsday is 20121221";
}
function handle($req, $log) {
$id = $req->id;
$log->write("\n\tfunction.php handle id=$id");
if('1104' == $id)
return 'guess?';
else if('531' == $id)
return 'score';
else if('1221' == $id)
return 'maybe doomsday';
else
return '404 not found';
}
?>
- 输出:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20CallPhp.call phpLog=
java give phpRootDir is data/php
doomsday is 20121221
function.php handle id=1104
CallPhp.test, id=1104 message=guess?
CallPhp.call phpLog=
java give phpRootDir is data/php
doomsday is 20121221
function.php handle id=531
CallPhp.test, id=531 message=score
CallPhp.call phpLog=
java give phpRootDir is data/php
doomsday is 20121221
function.php handle id=1221
CallPhp.test, id=1221 message=maybe doomsday
CallPhp.call phpLog=
java give phpRootDir is data/php
doomsday is 20121221
function.php handle id=110
CallPhp.test, id=110 message=404 not found
注意事项
- 由于是 Java 调用的 PHP,所以 PHP 里当前工作路径变成了 Java 的。
FileReader
加载 *.php 文件之后ScriptEngine.evel(FileReader)
的耗时大概为 230ms+,StringReader
时为 180ms+,速度都不咋滴,但是这不是我们项目急着考虑的问题,之前的 HTTP 方式也好不到哪去,优化留到以后再说。- PHP 的解释器运行路径配置:
-Dphp.java.bridge.php_exec=
。