转载自Spring整合Hessian
前言:
近日着手研究了一下Hessian的rmi方案,因为客户端是多种移动终端平台,本来想采用传说中的phprpc(hprose?)的,但看了下官方的文档,发现没有object-c的版本,故而放弃。
跟着hessian 的官方例子走,跑起来是没有问题的,但我在试着跟spring整合的时候,出了不少的问题。记录一下,方便自己以及路人,呵呵。
环境说明:
- spring version 3.0 RELEASE.
- Hessian version 4.0.7 WHATEVER.
- JEE version 2.5
实现步骤:
- 配置 web.xml ,添加对spring-web中 DispatcherServlet的定义.具体如下:
- <servlet>
- <servlet-name>test-remote</servlet-name>
- <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
- <init-param>
- <param-name>contextConfigLocation</param-name>
- <param-value>/WEB-INF/config/test-remote.xml</param-value>
- </init-param>
- <load-on-startup>4</load-on-startup>
- </servlet>
- <servlet-mapping>
- <servlet-name>test-remote</servlet-name>
- <url-pattern>/remote/*</url-pattern>
- </servlet-mapping>
A. 很多网友都说一定要在WEB-INF下面放入跟servlet-name相对应的 test-remote-servlet.xml 配置文件,实际上是不一定要那么处理的。如果指定了 contextConfigLocation的话,就可以解决这个问题。意味着spring不会强制要求你配置文件的位置。
B. DispatcherServlet是可以配置多个的,我这里还有一个test-local,mapping着 "/" 路径,他们之间并不会影响。当然可以单纯的配置多个 servlet-mapping.我只是想验证一下,结果说明确实是可以的。 - 传输对象类Space 的定义:
- packagetest.remote.dto;
- importjava.io.Serializable;
- importjava.util.Date;
- /**
- *Spacedatatransferobject.
- *@authorgogo
- *
- */
- publicclassSpaceimplementsSerializable{
- /**
- *autogeneratedserialVersionUid.
- */
- privatestaticfinallongserialVersionUID=5632812127919571530L;
- /**publicspacenameforpeopleinthespace.*/
- privateStringpublicName;
- privateStringprivateName;
- privatebooleanisActive;
- privateDatelastUpdatedTime;
- /**
- *setter&getter
- */
- @Override
- publicStringtoString(){
- StringBuilderbuffer=newStringBuilder("Space:");
- buffer.append("publicname:").append(publicName).append(",");
- buffer.append("privatename:").append(privateName).append(",");
- buffer.append("isactived:").append(isActive).append(",");
- buffer.append("lastUpdatedTime:").append(lastUpdatedTime.getTime());
- returnbuffer.toString();
- }
- }
- 服务接口的定义如下:
package test.remote.service;- importjava.util.List;
- importtest.remote.dto.Space;
- /**
- *
- *@authorgogo
- *
- */
- publicinterfaceSpaceService{
- ListshowSpaceNames();//返回名字集合
- SpacefindSpace(Stringid);//找到空间名字
- booleanupdateSpaceName(Stringname);//更新空间名字
- }
- 服务接口实现类:
package test.remote.service.impl;- importjava.util.ArrayList;
- importjava.util.Date;
- importjava.util.List;
- importorg.apache.commons.logging.Log;
- importorg.apache.commons.logging.LogFactory;
- importorg.springframework.remoting.caucho.HessianServiceExporter;
- importtest.remote.dto.Space;
- importtest.remote.service.SpaceService;
- /**
- *这个是一个远程接口的测试实现<br>
- *该接口会由spring的{@linkHessianServiceExporter}以Http服务的形式暴露.<br>
- *客户端会依赖Hessian实现
- *@seeHessianServiceExporter
- *@authorgogo
- *
- */
- publicclassSpaceServiceImplimplementsSpaceService{
- privatestaticfinalLoglog=LogFactory.getLog(SpaceServiceImpl.class);
- privateSpacecreateSpace(){
- Spacespace=newSpace();
- space.setPublicName("roosher-space");
- space.setPrivateName("my-private-room");
- space.setActive(true);
- space.setLastUpdatedTime(newDate());
- returnspace;
- }
- publicSpacefindSpace(Stringid){
- //TODOAuto-generatedmethodstub
- log.debug("findspaceidis:"+id);
- returncreateSpace();
- }
- publicListshowSpaceNames(){
- //TODOAuto-generatedmethodstub
- Listnames=newArrayList<String>();
- for(inti=0;i<10;i++){
- names.add("Hellospace"+i);
- }
- returnnames;
- }
- publicbooleanupdateSpaceName(Stringname){
- //TODOAuto-generatedmethodstub
- log.debug("updatedspacename:"+name);
- returntrue;
- }
- }
- test-remote.xml的内容:
- <?xmlversion="1.0"encoding="UTF-8"?>
- <beansxmlns="http://www.springframework.org/schema/beans"
- xmlns:context="http://www.springframework.org/schema/context"
- xmlns:p="http://www.springframework.org/schema/p"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://www.springframework.org/schema/beans
- http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
- http://www.springframework.org/schema/context
- http://www.springframework.org/schema/context/spring-context-3.0.xsd">
- <bean
- class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"
- p:order="1"></bean>
- <beanid="spaceService"class="test.service.impl.SpaceServiceImpl">
- </bean>
- <beanclass="org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter">
- </bean>
- <beanname="/SpaceHessian"
- class="org.springframework.remoting.caucho.HessianServiceExporter"
- p:serviceInterface="test.remote.service.SpaceService"
- p:service-ref="spaceService">
- </bean>
- <beanname="/SpaceBurlap"
- class="org.springframework.remoting.caucho.BurlapServiceExporter"
- p:serviceInterface="test.remote.service.SpaceService"
- p:service-ref="spaceService">
- </bean>
- </beans>
A. BeanNameUrlHandlerMapping 属性中的 p:order="1",可以不用配置.避免跟自己的冲突.
B. HttpRequestHandlerAdapter 在这里面非常关键,没有它可能会出现这种错误:
-- No adapter for handler Does your handler implement a supported interface like Controller ? HttpRequestHandlerAdapter它的作用就是让spring-mvc放出权限给下面的Exporter自己处理整个HTTP 流程.毕竟HessianServiceExporter也是实现的HttpRequestHandler - 客户端的两种实现:
A. 就是基于spring的实现,采用org.springframework.remoting.caucho.HessianProxyFactoryBean实现,相关配置如下:
- <beanid="spaceServiceHessian"
- class="org.springframework.remoting.caucho.HessianProxyFactoryBean">
- <propertyname="serviceUrl"
- value="http://localhost:8080/test/remote/SpaceHessian"/>
- <propertyname="serviceInterface"value="test.remote.service.SpaceService"/>
- </bean>
- <beanid="spaceServiceBurlap"
- class="org.springframework.remoting.caucho.BurlapProxyFactoryBean">
- <propertyname="serviceUrl"
- value="http://localhost:8080/test/remote/SpaceBurlap"/>
- <propertyname="serviceInterface"value="test.remote.service.SpaceService"/>
- </bean>
然后通过spring获取上下文之后,就可以直接注入 SpaceService service = context.getBean("spaceServiceBurlap");
B . 就是基于Hessian 自己提供的客户端,这里展示的是Java版本.
-
- packagetest.remote;
- importjava.net.MalformedURLException;
- importjava.util.List;
- importcom.caucho.hessian.client.HessianProxyFactory;
- importtest.remote.dto.Space;
- importtest.remote.service.SpaceService;
- /**
- *连接客户端。测试时要注意url的ip地址.
- *@seeSpace
- *@authorgogo
- *
- */
- publicclassSpaceClient{
- publicstaticvoidmain(String[]args){
- Stringurl="http://192.168.0.9:8080/test/remote/SpaceHessian";
- HessianProxyFactoryfactory=newHessianProxyFactory();
- try{
- SpaceServicespaceService=(SpaceService)factory.create(
- SpaceService.class,url);
- System.out.println(spaceService.findSpace("testid"));
- System.out.println(spaceService.updateSpaceName("whatever"));
- ListspaceNames=spaceService.showSpaceNames();
- System.out.println("\r\nGetspacenames:");
- for(inti=0;i<spaceNames.size();i++){
- System.out.print(spaceNames.get(i)+",");
- }
- System.out.println();
- System.out.println("spacenameslistfinished");
- }catch(MalformedURLExceptione){
- e.printStackTrace();
- }
- }
- }
- 测试结果:
- Space:publicname:roosher-space,privatename:my-private-room,isactived:true,
- lastUpdatedTime:1282196778538
- true
- Getspacenames:
- Hellospace0,Hellospace1,Hellospace2,Hellospace3,Hellospace4,Hellospace5
- ,Hellospace6,Hellospace7,Hellospace8,Hellospace9,
- spacenameslistfinished