Hessian整合Spring
含实例源码博客推荐:http://blog.csdn.net/julyness/article/details/49023581
简介:
Hessian是一个简单的连接Web服务的二进制协议。
- 客户端和服务端不依赖于其他任何jar,比起webService 它显得轻量许多,比如使用xfire包含核心库和客户端的jar,大小达到了10M ,而最新的hessian-4.0.7 jar大小也只有不到400K.
- 更适合二进制的传输,比起webService.Hessian的 传输速度要高于webService.
- 支持Java,c#,Flex(actionscrpit)
配置:
Hessian的访问分为客户端和服务端,首先都要有Hessian的jar包:
<dependency> <groupId>com.caucho</groupId> <artifactId>hessian</artifactId> <version>4.0.7</version> </dependency>
首先在pom中添加Hessian的依赖,确保客户端和服务端都有这个jar文件。
接下来我们来看看服务端怎么配置,首先是web.xml文件:
[html] view plain copy <!-- Hessian通过Servlet提供远程服务,需要将某个匹配的模式映射到hessian服务中, --> <!-- spring的dispatcherServlet能完成此功能,DispatcherServlet可将匹配模式的请求转发到Hessian服务, --> <!-- web.xml只是定义了“请求转发器”,该转发器将匹配/remoting/*的请求截获, 转发给context的bean处理。 --> <!-- 而HessianServiceExporter提供bean服务。 --> <servlet> <servlet-name>remoting</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>remoting</servlet-name> <url-pattern>/remoting/*</url-pattern> </servlet-mapping>
和Spring集成,我们不再使用这个类:
<servlet-class>com.caucho.hessian.server.HessianServlet</servlet-class>
这里是拦截所有包含remoting的请求,servlet的名称为remoting,注意这个名称,一会又用到。
然后看看这个文件remoting-servlet.xml是干什么用的呢?
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" 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 name="/userClientServiceRemote" class="org.springframework.remoting.caucho.HessianServiceExporter"> <property name="service" ref="userClientServiceRemote"/> <property name="serviceInterface" value="com.darren.comm.client.user.service.UserClientService"/> </bean> </beans>
首先在WEB-INF目录下,我们不用在别的地方配置去引用到这个文件,主要靠它的名字,它的名字是这样构成的servet-name + servlet,那么servlet-name是什么呢,就是上边提到的remoting,刚好,于是它的名字就叫remoting-servlet.xml
文件的内容就是提供一个bean供客户端使用, ref="userClientServiceRemote"/>这个依赖是通过Spring扫描后注入的一个bean。
注意:这个bean的名称要加斜线,和普通的bean不同
看一看接口的实现类是怎么配置的:
package com.darren.back.client.user.service.impl; import java.util.List; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import com.darren.back.back.user.service.UserService; import com.darren.comm.client.user.service.UserClientService; import com.darren.comm.exception.BusinessException; import com.darren.comm.user.po.User; import com.darren.comm.vo.ResultHandle; /** * 用户远程服务接口的实现 * * @author zhangpanfeng * */ @Component("userClientServiceRemote") public class UserClientServiceImpl implements UserClientService { private static final Log LOG = LogFactory.getLog(UserClientServiceImpl.class); /** * 注入用户服务 */ @Autowired private UserService userService; public ResultHandle<List<User>> findAllUsers() { ResultHandle<List<User>> resultHandle = new ResultHandle<List<User>>(); try { List<User> userList = userService.findAllUsers(); resultHandle.setContent(userList); } catch (BusinessException e) { LOG.error("Error method <findAllUsers>"); LOG.error(e); resultHandle.setErrorCode(e.getErrorCode()); resultHandle.setMessage(e.getMessage()); } return resultHandle; } }
好了,到此为止,服务端已配好了,接下来看看客户端怎么访问
客户端引入一个const.properties配置文件,内容如下:
darren_back.serviceUrl=http://localhost:9999/darren_back/remoting
注:这里服务端的端口是9999
这个url包含remoting,所以会走Hessian的路线。
客户端需要配一个bean:
<!-- 用户接口 --> <bean id="userClientService" class="org.springframework.remoting.caucho.HessianProxyFactoryBean"> <property name="serviceUrl" value="${darren_back.serviceUrl}/userClientServiceRemote" /> <property name="serviceInterface" value="com.darren.comm.client.user.service.UserClientService" /> <property name="chunkedPost" value="false" /> <property name="overloadEnabled" value="true" /> </bean>
这样的话,客户端的控制器就可以使用这个bean来访问服务端的内容了
package com.darren.web.user.action; import java.util.List; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.RequestMapping; import com.darren.comm.client.user.service.UserClientService; import com.darren.comm.exception.BusinessException; import com.darren.comm.user.po.User; import com.darren.comm.utils.StringUtil; import com.darren.comm.vo.ClientMessage; import com.darren.comm.vo.ResultHandle; import com.darren.web.user.service.UserService; /** * 用户控制器 * * @author zhangpanfeng * */ @Controller public class UserAction { @Autowired private UserClientService userClientService; @RequestMapping(value = "/login") public String login(Model model, User user) throws BusinessException { ClientMessage clientMessage = new ClientMessage(); String target = "/home"; ResultHandle<List<User>> resultHandle = userClientService.findAllUsers(); List<User> userList = resultHandle.getContent(); if (userList != null) { for (User u : userList) { System.out.println(u); } } return target; } }
我们运行一下看看结果:
[plain] view plain copy User [id=135e1bd1-4801-447a-aebb-d1d807c519fd, userName=222, password=BCBE3365E6AC95EA2C0343A2395834DD, createTime=Thu Apr 02 14:07:36 GMT+08:00 2015, updateTime=null] User [id=2c1214b4-ea09-42f9-9daa-5bf7de1edeaf, userName=qqq, password=B2CA678B4C936F905FB82F2733F5297F, createTime=Thu Apr 02 13:53:54 GMT+08:00 2015, updateTime=null] User [id=485786f6-7689-4f72-8c34-1539e6e3b67d, userName=111111, password=96E79218965EB72C92A549DD5A330112, createTime=Thu Apr 02 13:42:41 GMT+08:00 2015, updateTime=null] User [id=b0cab9c2-201c-4fc0-bf65-e4a8a8bb004a, userName=darren, password=96E79218965EB72C92A549DD5A330112, createTime=Wed Apr 01 17:31:32 GMT+08:00 2015, updateTime=null] User [id=e284f6d0-b871-49e8-9806-6f0118172ff5, userName=aaa, password=47BCE5C74F589F4867DBD57E9CA9F808, createTime=Thu Apr 02 13:56:59 GMT+08:00 2015, updateTime=null]
这是打印的结果信息,到此走通。
漏掉一个问题,我们需要看看ResultHandle类和User类
package com.darren.comm.vo; import java.io.Serializable; /** * 远程调用的返回对象 * * @author zhangpanfeng * * @param <T> */ public class ResultHandle<T> implements Serializable { private static final long serialVersionUID = -5396872858744255371L; /** * 返回信息 */ private String message; /** * 错误代码 */ private String errorCode; /** * 返回内容 */ private T content; public String getMessage() { return message; } public void setMessage(String message) { this.message = message; } public String getErrorCode() { return errorCode; } public void setErrorCode(String errorCode) { this.errorCode = errorCode; } public T getContent() { return content; } public void setContent(T content) { this.content = content; } }
package com.darren.comm.user.po; import com.darren.comm.base.po.BaseEntity; public class User extends BaseEntity { private static final long serialVersionUID = 8380375210393218806L; /** * 用户ID */ private String id; /** * 用户名 */ private String userName; /** * 密码 */ private String password; /** * 确认密码 */ private String confirmPassword; public String getId() { return id; } public void setId(String id) { this.id = id; } public String getUserName() { return userName; } public void setUserName(String userName) { this.userName = userName; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public String getConfirmPassword() { return confirmPassword; } public void setConfirmPassword(String confirmPassword) { this.confirmPassword = confirmPassword; } @Override public String toString() { return "User [id=" + id + ", userName=" + userName + ", password=" + password + ", createTime=" + createTime + ", updateTime=" + updateTime + "]"; } } [java] view plain copy package com.darren.comm.base.po; import java.io.Serializable; import java.util.Date; /** * 基础实体类 * * @author zhangpanfeng * */ public class BaseEntity implements Serializable { private static final long serialVersionUID = -7982965810132366752L; /** * 创建时间 */ protected Date createTime; /** * 更新时间 */ protected Date updateTime; public Date getCreateTime() { return createTime; } public void setCreateTime(Date createTime) { this.createTime = createTime; } public Date getUpdateTime() { return updateTime; } public void setUpdateTime(Date updateTime) { this.updateTime = updateTime; } }
a)当你想把的内存中的对象状态保存到一个文件中或者数据库中时候;
b)当你想用套接字在网络上传送对象的时候;
c)当你想通过RMI(Remote Method Invocation,远程方法调用)传输对象的时候;
所以是要序列化的,否则会报错的。