PHP和Java各自有着鲜明的特点:
PHP简单、易学,开发动态网页效率高,草根文化气息浓重,是语言世界的平民英雄。
Java强大而复杂,有众多高端功能,又有IMB、Oracle等企业大颚的追捧,是语言世界的贵族王子。
不管是平民英雄还是贵族王子,都不满足在各自领域称王,于是平民英雄祭出LAMP大旗,在PHP5新的对象模型帮衬下,硬要往上层阶层闯一闯,无奈金融、电信等王侯们不大欢迎;而贵族王子也非常重视WEB这个广大的基层社会,先制定Servlet/JSP法令,跟着又推出struts、JSF、Taglib、JSTL、Spring等系列政策,试图消除阶级等级概念,但实施手法贵族气太浓无法深得民心。
平民就是平民,贵族就是贵族,硬要将自己也视为对方阵营里的一员,只有一个结果:牵强。
-----------------------------------------
PHP结合Java是早已有的想法,PHP负责WEB层,Java负责业务和数据逻辑层,真是一对黄金组合。但PHP和Java是两个不同的语言,如何将他们结合在一起是个问题。实际上已经有了一些手段:如PHP中内置了调用Java的方法,开源的也有php-java-bridge,这里介绍的一个新的解决思路。
从操作系统层面观察: PHP和Java是系统中运行的不同进程,他们之间沟通属于进程间通信技术(IPC):
在传统的Unix环境中,IPC技术有:管道、消息队列、共享内存、信号量等,在当今TCP/IP流行的大背景下,IPC已经鲜有耳闻了,但在同一个系统中,IPC通信比基于TCP的socket通信在性能、资源占用方面有相当大的优势,所以今天我们重新挖掘IPC这门传统工艺,让它还发出新的光芒。
本文介绍的思路即是使用IPC技术来结合PHP和Java。
在Unix/Linux中,PHP基本提供了所有IPC的访问接口,这点不难想象,因为PHP可以看作是以C语言为核心的一个壳,而IPC是系统内核的组成部分,对外提供了一组C函数接口,因此PHP可以非常顺畅的运用IPC技术。而Java没那么幸运,为了追求夸平台性(Windows的IPC技术和Unix的不同),没有提供系统级的IPC访问,这也体现了Java的文化特色:为追求统一可牺牲效能。
好在Java有和C对接的JNI接口,可利用它来实现我们的设想,最后的思路如下图:
从上图中看出,PHP承担HTTP层的职责,而Java承担业务层的职责,他们通过System V Message Queue(消息队列,进程间通讯IPC中的一种)相互沟通,Java需要JNI的支持。
------------------------------------------------
通信问题解决了,下来就需要考虑通信内容的问题了。PHP和Java各有其语言内部定义的数据类型,当PHP数据传送到Java,或Java数据传送到PHP时,怎样进行转换呢? 很多人马上会想到使用xml,xml确是一种夸平台、能够很好描述对象模型的数据封装技术,但xml体积大传输速率慢,通讯两端解析也比较麻烦。
实际上,无论是PHP还是Java,在语言设计时都考虑了数据怎样传输和存储的问题,那就是序列化,例如EJB调用就是通过Java的序列化对象来传输数据的。
PHP的序列化非常巧妙,例如:
整形: $i = 5 序列化后是 i:5
字符串: $s = "abcd" 序列化后是 s:4:"abcd"
数组:$arr = array("a" => "value1", "b" => "value2") 序列化后是 a:2:{s:1:"a";s:6:"value1";s:1:"b";s:6:"value2";}
对象: class aaa{var $attr1 = 5; var $attr2 = "ABCD";} 序列化后是 O:3:"aaa":2:{s:5:"attr1";i:5;s:5:"attr2";s:4:"ABCD";}
简单而明了,不仅描述了数据结构,并带有数据原来的类型,问题得以解决。使用PHP序列化数据作为PHP和Java的通讯数据格式,不仅效能高,而且更加接近语言本意。
------------------------------------------------
开源项目LAJP 就是以上述思想为核心的实现技术,使用起来也非常简单,下面是一个示例程序:
* php端程序
<?php
require_once("../lajp/php_java.php"); //LAJP提供的程序脚本
//php类,映射到JavaBean类:cn.com.ail.test.Bean
class cn_com_ail_test_Bean
{
var $a = "v1";
var $b = "v2";
}
$p1 = "a";
$p2 = array(); //数组有两个元素,没有规定数组下标(默认下标是int类型0和1),映射到java的java.util.List类型
$p2[] = 10;
$p2[] = 20;
$p3 = new cn_com_ail_test_Bean;
//调用java服务
//lajp_call是“php_java.php”脚本提供的函数
//参数cn.com.ail.test.Objtest::method1表示调用java的cn.com.ail.test.Objtest类中的method1方法
//后面的$p1,$p2,$p3是向method1方法传递的参数。
$ret = lajp_call("cn.com.ail.test.Objtest::method1", $p1, $p2, $p3);
echo "返回信息:".$ret; //打印"OK,收到并返回字符串应答"
?>
* java端程序
//对应php中$p3的JavaBean
package cn.com.ail.test;
public class Bean
{
private String a;
private String b;
public String getA()
{
return a;
}
public void setA(String a)
{
this.a = a;
}
public String getB()
{
return b;
}
public void setB(String b)
{
this.b = b;
}
}
//java端服务
package cn.com.ail.test;
public class Objtest
{
//服务方法,只是简单的打印入参并返回简单字符串
public static final String method1(String param1, java.util.List param2, Bean param3)
{
System.out.println("$p1=" + param1);
for (int i = 0; i < param2.size(); i++)
{
System.out.printf("$p2[%i]=%i\n", i, (Integer)param2.get(i));
}
System.out.println("$p3->a=" + param3.getA());
System.out.println("$p3->b=" + param3.getB());
//返回
return "OK,收到并返回字符串应答";
}
}
LAJP的相关资料,可查看其网站:http://code.google.com/p/lajp/
如对本文有疑问,请提交到交流论坛,广大热心网友会为你解答!! 点击进入论坛