spring和hessian整合--基于HessianServiceExporter & BurlapServiceExporter
程序员文章站
2022-05-13 08:16:16
...
前言:
近日着手研究了一下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>
Tips:
A. 很多网友都说一定要在WEB-INF下面放入跟servlet-name相对应的 test-remote-servlet.xml 配置文件,实际上是不一定要那么处理的。如果指定了 contextConfigLocation的话,就可以解决这个问题。意味着spring不会强制要求你配置文件的位置。
B. DispatcherServlet是可以配置多个的,我这里还有一个test-local,mapping着 "/" 路径,他们之间并不会影响。当然可以单纯的配置多个 servlet-mapping.我只是想验证一下,结果说明确实是可以的。 - 传输对象类Space 的定义:
package test.remote.dto; import java.io.Serializable; import java.util.Date; /** * Space data transfer object. * @author gogo * */ public class Space implements Serializable{ /** * auto generated serialVersionUid. */ private static final long serialVersionUID = 5632812127919571530L; /** public space name for people in the space.*/ private String publicName; private String privateName; private boolean isActive; private Date lastUpdatedTime; /** * setter & getter */ @Override public String toString() { StringBuilder buffer = new StringBuilder("Space:"); buffer.append("public name:").append(publicName).append(", "); buffer.append("private name:").append(privateName).append(", "); buffer.append("is actived:").append(isActive).append(", "); buffer.append("lastUpdatedTime:").append(lastUpdatedTime.getTime()); return buffer.toString(); } }
- 服务接口的定义如下:
package test.remote.service;import java.util.List; import test.remote.dto.Space; /** * * @author gogo * */ public interface SpaceService { List showSpaceNames(); //返回名字集合 Space findSpace(String id);//找到空间名字 boolean updateSpaceName(String name); //更新空间名字 }
- 服务接口实现类:
package test.remote.service.impl;import java.util.ArrayList; import java.util.Date; import java.util.List; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.remoting.caucho.HessianServiceExporter; import test.remote.dto.Space; import test.remote.service.SpaceService; /** * 这个是一个远程接口的测试实现<br> * 该接口会由spring的 {@link HessianServiceExporter}以Http服务的形式暴露.<br> * 客户端会依赖Hessian实现 * @see HessianServiceExporter * @author gogo * */ public class SpaceServiceImpl implements SpaceService{ private static final Log log = LogFactory.getLog(SpaceServiceImpl.class); private Space createSpace() { Space space = new Space(); space.setPublicName("roosher-space"); space.setPrivateName("my-private-room"); space.setActive(true); space.setLastUpdatedTime(new Date()); return space; } public Space findSpace(String id) { // TODO Auto-generated method stub log.debug("find space id is :" + id); return createSpace(); } public List showSpaceNames() { // TODO Auto-generated method stub List names = new ArrayList<String>(); for (int i = 0; i < 10; i++) { names.add("Hello space "+ i); } return names; } public boolean updateSpaceName(String name) { // TODO Auto-generated method stub log.debug("updated space name : " + name ); return true; } }
- test-remote.xml的内容:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="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> <bean id="spaceService" class="test.service.impl.SpaceServiceImpl"> </bean> <bean class="org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter"> </bean> <bean name="/SpaceHessian" class="org.springframework.remoting.caucho.HessianServiceExporter" p:serviceInterface="test.remote.service.SpaceService" p:service-ref="spaceService"> </bean> <bean name="/SpaceBurlap" class="org.springframework.remoting.caucho.BurlapServiceExporter" p:serviceInterface="test.remote.service.SpaceService" p:service-ref="spaceService"> </bean> </beans>
Tips:
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实现,相关配置如下:
<bean id="spaceServiceHessian" class="org.springframework.remoting.caucho.HessianProxyFactoryBean"> <property name="serviceUrl" value="http://localhost:8080/test/remote/SpaceHessian" /> <property name="serviceInterface" value="test.remote.service.SpaceService" /> </bean> <bean id="spaceServiceBurlap" class="org.springframework.remoting.caucho.BurlapProxyFactoryBean"> <property name="serviceUrl" value="http://localhost:8080/test/remote/SpaceBurlap" /> <property name="serviceInterface" value="test.remote.service.SpaceService" /> </bean>
注意到里面的URL了没? 其中 http://localhost:8080/test/remote/SpaceHessian 的/SpaceHessian 对应的是之前在remote-test.xml中配置的<bean name="/SpaceHessian"> </bean>的URI.
然后通过spring获取上下文之后,就可以直接注入 SpaceService service = context.getBean("spaceServiceBurlap");
B . 就是基于Hessian 自己提供的客户端,这里展示的是Java版本.
-
package test.remote; import java.net.MalformedURLException; import java.util.List; import com.caucho.hessian.client.HessianProxyFactory; import test.remote.dto.Space; import test.remote.service.SpaceService; /** * 连接客户端。测试时要注意 url的ip地址. * @see Space * @author gogo * */ public class SpaceClient { public static void main(String[] args) { String url = "http://192.168.0.9:8080/test/remote/SpaceHessian"; HessianProxyFactory factory = new HessianProxyFactory(); try { SpaceService spaceService = (SpaceService) factory.create( SpaceService.class, url); System.out.println(spaceService.findSpace("testid")); System.out.println(spaceService.updateSpaceName("whatever")); List spaceNames = spaceService.showSpaceNames(); System.out.println("\r\nGet space names:"); for (int i = 0; i < spaceNames.size(); i++) { System.out.print(spaceNames.get(i) + ", "); } System.out.println(); System.out.println("space names list finished"); } catch (MalformedURLException e) { e.printStackTrace(); } } }
如果后台没有什么太大的问题,直接跑起来就可以测试了。
- 测试结果:
Space:public name:roosher-space, private name:my-private-room, is actived:true, lastUpdatedTime:1282196778538 true Get space names: Hello space 0, Hello space 1, Hello space 2, Hello space 3, Hello space 4, Hello space 5 , Hello space 6, Hello space 7, Hello space 8, Hello space 9, space names list finished
- Cheers! 第一次认真的写博.但愿对大家有所帮助
。