Spring提供类用于集成各种远程访问技术。这种对远程访问的支持可以降低你在用POJO实现支持远程访问业务时的开发难度。目前,Spring提供对下面四种远程访问技术的支持:
远程方法调用(RMI)。通过使用RmiProxyFactoryBean和RmiServiceExporter,Spring支持传统的RMI(使用java.rmi.Remote interfaces 和 java.rmi.RemoteException)和通过RMI调用器(可以使用任何Java接口)的透明远程调用。
Spring的HTTP调用器。Spring提供一种特殊的远程调用策略支持任何Java接口(象RMI调用器一样),它允许Java序列化能够通过HTTP传送。对应的支持类是HttpInvokerProxyFactoryBean和HttpInvokerServiceExporter。
Hessian。通过使用HessianProxyFactoryBean和HessianServiceExporter,你可以使用Caucho提供的轻量级基于HTTP的二进制协议透明地提供你的业务。
Burlap。Burlap是基于XML的,它可以完全代替Hessian。Spring提供的支持类有BurlapProxyFactoryBean和BurlapServiceExporter。
JAX RPC (TODO).
RMI是不能够穿越防火墙的,在网上也查了一些资料,但根据其提供的方法都没有成功,唉,功夫不负有心人,经过一番努力,还是把它实现了,其实这东西就是一层窗纸,捅破了也没有什么太难得,废话不说了,我们开始吧。(不好意思,还得再说一句废话:得益于罗士飞的那本spring教程代码)。
在此之前,我先把目录结构抓取个图像给大家看看。
当然首先要把spring的相关依赖的jar包引入了。这里就不能描述了。
先写服务器段代码:
1. 定义接口 ILogPerson.java
package com.openv.spring; public interface ILogPerson { public String getPersion(PersonVO personVO); }
2. 定义POJO PersonVO.java
package com.openv.spring; import java.io.Serializable; public class PersonVO implements Serializable { private String firstname; private String lastname; public String getFirstname() { return firstname; } public void setFirstname(String firstname) { this.firstname = firstname; } public String getLastname() { return lastname; } public void setLastname(String lastname) { this.lastname = lastname; } }
注意:这里的PersonVO.java 必须继承Serializable 以实现序列化,不然会抱错,谨记!
3. 定义实现:LogPerson.java
package com.openv.spring; public class LogPerson implements ILogPerson{ public String getPersion(PersonVO personVO) { return personVO.getFirstname()+" @#@ "+personVO.getLastname(); } }
4. 定义spring的依赖注入的文件appcontextrmiserver.xml
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd"> <beans> <bean id="logPerson" class="com.openv.spring.LogPerson"/> <bean id="logPersonService" class="org.springframework.remoting.rmi.RmiServiceExporter"> <!-- RmiServiceExporter 对服务名没有特殊要求 --> <property name="serviceName"> <value>LogPerson</value> </property> <property name="service"> <ref bean="logPerson"/> </property> <property name="serviceInterface"> <value>com.openv.spring.ILogPerson</value> </property> <!-- 避免与默认的RMI注册端口冲突,因此修改为1200 --> <property name="registryPort"> <value>1200</value> </property> </bean> </beans>
5. 定义运行rmi服务的类: LogPersonRmiServer.java
package com.openv.spring; import org.springframework.core.io.Resource; import org.springframework.core.io.ClassPathResource; import org.springframework.beans.factory.xml.XmlBeanFactory; import org.springframework.beans.factory.BeanFactory; import java.io.Serializable; public class LogPersonRmiServer{ public static void main(String[] args) { //初始化appcontextrmiserver.xml Resource sresource = new ClassPathResource("appcontextrmiserver.xml"); BeanFactory sfactory = new XmlBeanFactory(sresource); //注册RMI sfactory.getBean("logPersonService"); } }
运行main函数,rmi服务就启动了。
下面写客户调用端的代码了。
大家从目录图中看一下,为了调试方便,我把服务端和客户端写在了一起。在实际的项目中,客户端的代码是不可能和服务器端在一起的,那样还叫什么远程调用呀,呵呵。在实际的项目中,我们应该把接口ILogPerson.java和POJO PersonVO.java 文件打成jar包给客户端引用即可,而实现是在服务器端完成。
下面我们可以在另外一台计算机(为了强调远程嘛,呵呵)上新建立一个客户端调用的工程。客户端很简单
1. 引入spring的依赖文件和 接口ILogPerson.java和POJO PersonVO.java 文件打成jar包
2. spring的依赖注入的文件 appcontextrmiclient.xml
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd"> <beans> <bean id="LogPerson" class="org.springframework.remoting.rmi.RmiProxyFactoryBean"> <property name="serviceUrl"><value>rmi://77.20.64.237:1200/LogPerson</value></property> <property name="serviceInterface"><value>com.openv.spring.ILogPerson</value></property> </bean> </beans>
3. 调用文件 LogPersonRmiClient.java
package com.openv.spring; import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.xml.XmlBeanFactory; import org.springframework.core.io.ClassPathResource; import org.springframework.core.io.Resource; public class LogPersonRmiClient { public static void main(String[] args) { //初始化appcontextrmiclient.xml Resource cresource = new ClassPathResource("appcontextrmiclient.xml"); BeanFactory cfactory = new XmlBeanFactory(cresource); //实例化Person值对象 PersonVO personVO = new PersonVO(); personVO.setFirstname("Luo2"); personVO.setLastname("Shifei"); //获得RMI服务 ILogPerson clientLog = (ILogPerson) cfactory.getBean("LogPerson"); //调用RMI服务 System.out.println("==>> " + clientLog.getPersion(personVO)); } }
虽然简单,但是也有四五个文件,其实每个文件不是很复杂,只要耐着心思把其一个个写出来,就能成功,如果运行结果出来了,你对rmi的各种疑惑也就形如冰释了。我也搞了大半天才将其实现,愿能给参看的朋友一些提示。
经过spring的封装,rmi的复杂过程得到了很大的简化,基本变成了配置的过程,什么rmi手工注册和声成什么乱七八糟的文件都省略了。不过不能穿越防火墙,下面我们在介绍一种可以穿越防火墙的spring远程调用hissian。