Hessian怎样实现远程调用
1.Spring中除了提供HTTP调用器方式的远程调用,还对第三方的远程调用实现提供了支持,其中提供了对Hessian的支持。
Hessian是由Caocho公司发布的一个轻量级的二进制协议远程调用实现方案,Hessian也是基于HTTP协议的,其工作原理如下:
(1).客户端:
a.发送远程调用请求:
客户端程序—>发送远程调用请求—>Hessian客户端拦截器—>封装远程调用请求—>Hessian代理—>通过HTTP协议发送远程请求代理到服务端。
b.接收远程调用响应:
远程调用结果—>HTTP响应—>客户端。
(1).服务端:
a.接收远程调用请求:
远程调用HTTP请求—>HessianServiceExporter接收请求—>HessianExporter将远程调用对象封装为HessianSkeleton框架—> HessianSkeleton处理远程调用请求。
b.返回远程调用响应:
HessianSkeleton封装远程调用处理结果—>HTTP响应—>客户端。
本文章通过分析Spring对Hessian支持的相关源码,了解Spring对Hessian支持的具体实现。
2.Hessian的客户端配置:
Hessian的客户端需要做类似如下的配置:
[xhtml] view plaincopy
<bean id=”hessianProxy” class=”org.springframework.remoting.caucho.HessianProxyFactoryBean”>
<property name=”serviceUrl”>
<value>http://hostAddress:8080/serviceUrlvalue>
property>
<property name=”serviceInterface”>
<value>远程调用服务接口value>
]property>
bean>
和HTTP调用器的配置类似,都需要配置远程调用请求的url,这个url要和服务端的url一致,Spring通过DispatcherServlet找到服务端对于的请求url。
HessianProxyFactoryBean是Spring中管理Hessian客户端的IoC容器,主要负责产生服务端远程调用代理和对客户端远程调用的拦截器设置。
3.HessianProxyFactoryBean:
HessianProxyFactoryBean生成远程调用代理和客户端远程调用拦截器设置,其源码如下:
[java] view plaincopy
public class HessianProxyFactoryBean extends HessianClientInterceptor implements FactoryBean {
//远程调用代理对象
private Object serviceProxy;
//Spring IoC容器依赖注入完成后的回调方法
public void afterPropertiesSet() {
//首先调用父类HessianClientInterceptor的回调方法
super.afterPropertiesSet();
//创建远程调用代理对象并设置拦截器,注意这个this参数,因为//HessianProxyFactoryBean继承HessianClientInterceptor,因此其本身也
//是Hassien客户端拦截器
this.serviceProxy = new ProxyFactory(getServiceInterface(), this).getProxy(getBeanClassLoader());
}
//Spring IoC容器的接口FactoryBean产生对象的方法,客户端通过该方法获取被管
//理的远程调用代理
public Object getObject() {
return this.serviceProxy;
}
//获取对象的类型
public Class getObjectType() {
return getServiceInterface();
}
//对象是否是单态类型,Spring默认管理的对象都是单态模式
public boolean isSingleton() {
return true;
}
}
HessianProxyFactoryBean最核心的功能就是在IoC容器回调方法中产生远程调用代理对象,在产生远程调用代理对象时,将代理对象的拦截器设置为其父类HessianClientInterceptor。
4.HessianClientInterceptor拦截客户端的远程调用请求:
HessianClientInterceptor对客户端的远程调用进行拦截,为客户端的远程调用创建Hessian代理,通过Hessian代理调用服务端远程调用对象,其源码如下:
[java] view plaincopy
public class HessianClientInterceptor extends UrlBasedRemoteAccessor implements MethodInterceptor {
//创建Hessiann代理工厂
private HessianProxyFactory proxyFactory = new HessianProxyFactory();
//Hessian代理
private Object hessianProxy;
//设置Hessian代理工厂
public void setProxyFactory(HessianProxyFactory proxyFactory) {
this.proxyFactory = (proxyFactory != null ? proxyFactory : new HessianProxyFactory());
}
//设置Hessian序列化工厂
public void setSerializerFactory(SerializerFactory serializerFactory) {
this.proxyFactory.setSerializerFactory(serializerFactory);
}
//设置Hessian是否发送java集合类型对象
public void setSendCollectionType(boolean sendCollectionType) {
this.proxyFactory.getSerializerFactory().setSendCollectionType(sendCollectionType);
}
//设置远程调用时是否重载方法
public void setOverloadEnabled(boolean overloadEnabled) {
this.proxyFactory.setOverloadEnabled(overloadEnabled);
}
//设置远程调用用户名
public void setUsername(String username) {
this.proxyFactory.setUser(username);
}
//设置远程调用密码
public void setPassword(String password) {
this.proxyFactory.setPassword(password);
}
//设置是否使用Hessian的Debug调试模式
public void setDebug(boolean debug) {
this.proxyFactory.setDebug(debug);
}
//设置是否使用chunked端口发送Hessian请求
public void setChunkedPost(boolean chunkedPost) {
this.proxyFactory.setChunkedPost(chunkedPost);
}
//设置Hessian等待响应的超时时长
public void setReadTimeout(long timeout) {
this.proxyFactory.setReadTimeout(timeout);
}
//设置是否使用Hessain版本2协议解析请求和响应
public void setHessian2(boolean hessian2) {
this.proxyFactory.setHessian2Request(hessian2);
this.proxyFactory.setHessian2Reply(hessian2);
}
//设置是否使用Hessian版本2协议解析请求
public void setHessian2Request(boolean hessian2) {
this.proxyFactory.setHessian2Request(hessian2);
}
//设置是否使用Hessian版本2协议解析响应
public void setHessian2Reply(boolean hessian2) {
this.proxyFactory.setHessian2Reply(hessian2);
}
//子类HessianProxyFactoryBean的回调方法调用此回调方法
public void afterPropertiesSet() {
//调用其父类UrlBasedRemoteAccessor的回调方法获取客户端配置的请求url
super.afterPropertiesSet();
//初始化Hessian代理
prepare();
}
//初始化Hessian代理
public void prepare() throws RemoteLookupFailureException {
try {
//创建Hessian代理
this.hessianProxy = createHessianProxy(this.proxyFactory);
}
catch (MalformedURLException ex) {
throw new RemoteLookupFailureException("Service URL [" + getServiceUrl() + "] is invalid", ex);
}
}
//创建Hessian代理
protected Object createHessianProxy(HessianProxyFactory proxyFactory) throws MalformedURLException {
Assert.notNull(getServiceInterface(), "'serviceInterface' is required");
//使用Hessian代理工厂创建Hessian代理
return proxyFactory.create(getServiceInterface(), getServiceUrl());
}
//拦截器客户端请求的方法
public Object invoke(MethodInvocation invocation) throws Throwable {
if (this.hessianProxy == null) {
throw new IllegalStateException("HessianClientInterceptor is not properly initialized - " +
"invoke 'prepare' before attempting any operations");
}
//获取当前环境中线程类加载器
ClassLoader originalClassLoader = overrideThreadContextClassLoader();
try {
//调用Hessian代理的方法,是Hessian远程调用的入口方法,使用JDK反射机制
return invocation.getMethod().invoke(this.hessianProxy, invocation.getArguments());
}
//处理Hessian远程调用中的异常
catch (InvocationTargetException ex) {
Throwable targetEx = ex.getTargetException();
if (targetEx instanceof InvocationTargetException) {
targetEx = ((InvocationTargetException) targetEx).getTargetException();
}
if (targetEx instanceof HessianConnectionException) {
throw convertHessianAccessException(targetEx);
}
else if (targetEx instanceof HessianException || targetEx instanceof HessianRuntimeException) {
Throwable cause = targetEx.getCause();
throw convertHessianAccessException(cause != null ? cause : targetEx);
}
else if (targetEx instanceof UndeclaredThrowableException) {
UndeclaredThrowableException utex = (UndeclaredThrowableException) targetEx;
throw convertHessianAccessException(utex.getUndeclaredThrowable());
}
else {
throw targetEx;
}
}
catch (Throwable ex) {
throw new RemoteProxyFailureException(
"Failed to invoke Hessian proxy for remote service [" + getServiceUrl() + "]", ex);
}
//重置类加载器
finally {
resetThreadContextClassLoader(originalClassLoader);
}
}
//将Hessian异常转换为Spring远程调用异常
protected RemoteAccessException convertHessianAccessException(Throwable ex) {
if (ex instanceof HessianConnectionException || ex instanceof ConnectException) {
return new RemoteConnectFailureException(
"Cannot connect to Hessian remote service at [" + getServiceUrl() + "]", ex);
}
else {
return new RemoteAccessException(
"Cannot access Hessian remote service at [" + getServiceUrl() + "]", ex);
}
}
}
通过上面对HessianClientInterceptor的源码分析,我们可以看到Hessian客户端拦截器提供的最重要的方法是对远程调用拦截的方法invoke,在该方法中使用JDK的反射机制调用Hessian代理对象的指定方法。而Hessian代理是由Hessain代理器工厂HessianProxyFactory产生的,这个Hessian代理器工厂是有Hessian提供的。
5.Hessian服务器端配置:
在Hessian的服务端需要进行类似如下的配置:
[xhtml] view plaincopy
<bean id=”/serviceUrl” class=”org.springframework.remoting.caucho.HessianServiceExporter”>
<property name=”service”>
<ref bean=”service”/>
property>
<property name=”serviceInterface”>
<value>远程服务接口value>
property>
bean>
Spring的HessianServiceExporter把远程调用服务整合到Spring MVC框架中,通过DispatcherServlet将客户端请求转发到服务器端相应的请求url远程对象上。
注意:serviceUrl要和客户端serviceUrl中配置的相同,service即是服务端提供服务的远程对象。
6.HessianServiceExporter处理Hessian远程调用请求:
HessianServiceExporter接收客户端的远程调用请求,并调用HessianExporter具体处理远程调用,并且远程调用结果封装到HTTP响应中返回,e家装网源码如下:
[java] view plaincopy
public class HessianServiceExporter extends HessianExporter implements HttpRequestHandler {
//处理Hessian请求,并将处理结果封装为Hessian响应返回
public void handleRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//Hessian只支持HTTP的POST方法
if (!"POST".equals(request.getMethod())) {
throw new HttpRequestMethodNotSupportedException(request.getMethod(),
new String[] {"POST"}, "HessianServiceExporter only supports POST requests");
}
//设置Hessian响应内容类型为:application/x-hessian
response.setContentType(CONTENT_TYPE_HESSIAN);
try {
//HessianExporter真正处理Hessian请求和封装Hessian响应的方法
invoke(request.getInputStream(), response.getOutputStream());
}
catch (Throwable ex) {
throw new NestedServletException("Hessian skeleton invocation failed", ex);
}
}
}
7.HessianExporter处理Hessian请求并将结果封装为HTTP响应:
[java] view plaincopy
public class HessianExporter extends RemoteExporter implements InitializingBean {
//Hessian HTTP响应内容类型
public static final String CONTENT_TYPE_HESSIAN = "application/x-hessian";
//Hessian序列化工厂
private SerializerFactory serializerFactory = new SerializerFactory();
//Hessian Debug日志
private Log debugLogger;
//Hessian服务端框架
private HessianSkeleton skeleton;
//设置Hessian序列化工厂
public void setSerializerFactory(SerializerFactory serializerFactory) {
this.serializerFactory = (serializerFactory != null ? serializerFactory : new SerializerFactory());
}
//设置序列化集合发送java集合类型
public void setSendCollectionType(boolean sendCollectionType) {
this.serializerFactory.setSendCollectionType(sendCollectionType);
}
//设置Hessian调试模式
public void setDebug(boolean debug) {
this.debugLogger = (debug ? logger : null);
}
//回调方法
public void afterPropertiesSet() {
prepare();
}
//初始化Hessian服务框架
public void prepare() {
//这里调用父类RemoteExporter的方法检查服务提供类、服务接口
checkService();
checkServiceInterface();
//创建远程服务类的Hessian框架
this.skeleton = new HessianSkeleton(getProxyForService(), getServiceInterface());
}
//远程调用处理入口
public void invoke(InputStream inputStream, OutputStream outputStream) throws Throwable {
Assert.notNull(this.skeleton, "Hessian exporter has not been initialized");
doInvoke(this.skeleton, inputStream, outputStream);
}
//远程调用处理方法
protected void doInvoke(HessianSkeleton skeleton, InputStream inputStream, OutputStream outputStream)
throws Throwable {
//获取类加载器
ClassLoader originalClassLoader = overrideThreadContextClassLoader();
try {
InputStream isToUse = inputStream;
OutputStream osToUse = outputStream;
//设置Hessian调试日志
if (this.debugLogger != null && this.debugLogger.isDebugEnabled()) {
PrintWriter debugWriter = new PrintWriter(new CommonsLogWriter(this.debugLogger));
HessianDebugInputStream dis = new HessianDebugInputStream(inputStream, debugWriter);
dis.startTop2();
HessianDebugOutputStream dos = new HessianDebugOutputStream(outputStream, debugWriter);
dos.startTop2();
isToUse = dis;
osToUse = dos;
}
if (!isToUse.markSupported()) {
isToUse = new BufferedInputStream(isToUse);
isToUse.mark(1);
}
int code = isToUse.read();
int major;
int minor;
AbstractHessianInput in;
AbstractHessianOutput out;
//根据客户端不同的Hessian版本,设置不同的Hessian抽象输入/输出
//Hessian2.0
if (code == 'H') {
major = isToUse.read();
minor = isToUse.read();
if (major != 0x02) {
throw new IOException("Version " + major + "." + minor + " is not understood");
}
in = new Hessian2Input(isToUse);
out = new Hessian2Output(osToUse);
in.readCall();
}
//Hessian2.0
else if (code == 'C') {
isToUse.reset();
in = new Hessian2Input(isToUse);
out = new Hessian2Output(osToUse);
in.readCall();
}
//Hessian1.0
else if (code == 'c') {
major = isToUse.read();
minor = isToUse.read();
in = new HessianInput(isToUse);
if (major >= 2) {
out = new Hessian2Output(osToUse);
}
else {
out = new HessianOutput(osToUse);
}
}
else {
throw new IOException("Expected 'H'/'C' (Hessian 2.0) or 'c' (Hessian 1.0) in hessian input at " + code);
}
//设置Hessian序列化工厂
if (this.serializerFactory != null) {
in.setSerializerFactory(this.serializerFactory);
out.setSerializerFactory(this.serializerFactory);
}
try {
//通过服务端远程对象的Hessian框架处理远程调用
skeleton.invoke(in, out);
}
finally {
try {
in.close();
isToUse.close();
}
catch (IOException ex) {
}
try {
out.close();
osToUse.close();
}
catch (IOException ex) {
}
}
}
//重置类加载器
finally {
resetThreadContextClassLoader(originalClassLoader);
}
}
}
通过上面对HessianExporter源码分析,我们看到真正进行远程调用处理的是由Hessian提供的服务端HessianSkeleton。
Hessian怎样实现远程调用的更多相关文章
- Hessian轻量级二进制远程调用框架
Hessian轻量级二进制远程调用框架 Hessian是一个轻量级的二进制远程调用框架,官方文档地址,它主要包括Hessian远程调用协议.Hessian序列化协议以及客户端服务端代理等几部分,关于H ...
- [转载] 基于Dubbo的Hessian协议实现远程调用
转载自http://shiyanjun.cn/archives/349.html Dubbo基于Hessian实现了自己Hessian协议,可以直接通过配置的Dubbo内置的其他协议,在服务消费方进行 ...
- 基于Dubbo的Hessian协议实现远程调用
Dubbo基于Hessian实现了自己Hessian协议,可以直接通过配置的Dubbo内置的其他协议,在服务消费方进行远程调用,也就是说,服务调用方需要使用Java语言来基于Dubbo调用提供方服务, ...
- Spring远程调用技术<2>-Hessian和Burlap
上篇谈到RMI技术,加上Spring的封装,用起来很方便,但也有一些限制 这里的Hessian和Burlap解决了上篇提到的限制,因为他们是基于http的轻量级远程服务. Hessian,和RMI一样 ...
- Hessian——轻量级远程调用方案
Hessian是caucho公司开发的一种基于二进制RPC协议(Remote Procedure Call protocol)的轻量级远程调用框架.具有多种语言的实现,但用的最多的当然是Java实现 ...
- 远程调用之RMI、Hessian、Burlap、Httpinvoker、WebService的比较
一.综述 本文比较了RMI.Hessian.Burlap.Httpinvoker.WebService5这种通讯协议的在不同的数据结构和不同数据量时的传输性能. RMI是java语言本身提供的远程通讯 ...
- 远程调用——hessian使用入门
Hessian是一个轻量级的remoting onhttp工具,使用简单的方法提供了RMI的功能. 相比WebService,Hessian更简单.快捷.采用的是二进制RPC协议,因为采用的是二进制协 ...
- [转]Hessian——轻量级远程调用方案
Hessian是caucho公司开发的一种基于二进制RPC协议(Remote Procedure Call protocol)的轻量级远程调用框架.具有多种语言的实现,但用的最多的当然是Java实现 ...
- Java 远程调用之Hessian简例
1. [代码]1.服务接口(Hello.java) package server; public interface Hello { String hello(String name);}2. [代码 ...
随机推荐
- Qt quick 编程
greaterThan(QT_MAJOR_VERSION,4):QT += widgets.在Qt 5之前,没有独立的QtWidgets模块,Qt Widgets包含在QtGui模块中. TARGET ...
- Python for Infomatics 第12章 网络编程四(译)
注:文章原文为Dr. Charles Severance 的 <Python for Informatics>.文中代码用3.4版改写,并在本机测试通过. 12.7 用BeautifulS ...
- IOS 开发调用打电话,发短信
1.调用 自带mail[[UIApplication sharedApplication] openURL:[NSURL URLWithString:@"mailto://admin@hzl ...
- STL学习之vector
vector是一个线性顺序结构.相当于数组,但其大小可以不预先指定,并且自动扩展.它可以像指针一样被操作,由于它的特性我们完全可以将vector看做动态数组. 特点: 1.指定一块如同数组一样的连续存 ...
- assert_option()可以用来对assert()进行一些约束和控制
一.evaleval用法:eval() 函数把字符串按照 PHP 代码来计算.该字符串必须是合法的 PHP 代码,且必须以分号结尾.如果没有在代码字符串中调用 return 语句,则返回 NULL.如 ...
- Java 中的值传递和参数传递
Java中没有指针,所以也没有引用传递了,仅仅有值传递不过可以通过对象的方式来实现引用传递 类似java没有多继承 但可以用多次implements 接口实现多继承的功能 值传递:方法调用时,实际参数 ...
- C#网络编程之---TCP协议的同步通信(二)
上一篇学习日记C#网络编程之--TCP协议(一)中以服务端接受客户端的请求连接结尾既然服务端已经与客户端建立了连接,那么沟通通道已经打通,载满数据的小火车就可以彼此传送和接收了.现在让我们来看看数据的 ...
- 阿里云服务器Linux CentOS安装配置(二)yum安装svn
阿里云服务器Linux CentOS安装配置(二)yum安装svn 1.secureCRT连接服务器 2.先创建一个文件夹,用来按自己的习惯来,用来存放数据 mkdir /data 3.yum安装sv ...
- [bzoj2463]谁能赢呢
我们通过观察可以发现,当n为偶数时,一定可以转化为一种先手必胜态,即棋盘可以被骨牌所覆盖, 如果n是奇数,那么去掉一格后一定能被1*2的骨牌覆盖,但是先手从左上角走,就进入了这个S态(必胜态),那么和 ...
- Execel(导出新方法):
#region 新方法 //var sbHtml = new StringBuilder(); //sbHtml.Append("<table border='1' cellspaci ...