hessian浅析

Hessian用于远程调用,是基于Http的。它采用的是二进制RPC协议(Binary),具有轻量、传输量小、平台无关的特点。协议开源,除了java,还有支持很多其他语言。无事务,适合安全性要求不高的项目,一般用在内部系统间调用。

1. 配置及使用

使用Spring 集成Hessian

###服务端

  • 接口类
1
2
3
4
5
6
7
8
9
10
11
package com.example.intf;
/**
* Hession接口
*/
public interface Ihello {
/*
* 调用方法
*/
public String invokeSay(String name);
}
  • 实现类
1
2
3
4
5
6
7
8
9
10
11
12
13
package com.example.server;
import com.example.intf.Ihello;
/**
* hession服务实现类
*/
public class HelloServer implements Ihello {
public String invokeSay(String name) {
return "Hello " + name;
}
}
  • web.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
<web-app>
<servlet>
<servlet-name>hessian</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath*:/conf/hessian-servlet.xml</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>hessian</servlet-name>
<url-pattern>/hessian/*</url-pattern>
</servlet-mapping>
</web-app>
  • hessian-servlet.xml
1
2
3
4
5
6
7
8
9
10
11
12
<?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:jee="http://www.springframework.org/schema/jee"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee.xsd">
<bean id="helloService" class="com.example.server.HelloServer" />
<bean name="/helloServer"
class="org.springframework.remoting.caucho.HessianServiceExporter">
<property name="service" ref="helloService" />
<property name="serviceInterface" value="com.example.intf.Ihello" />
</bean>
</beans>

客户端

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
package com.example.client;
import java.net.MalformedURLException;
import com.caucho.hessian.client.HessianProxyFactory;
import com.example.intf.Ihello;
/**
*
* Hessian客户端,调用hession接口
*/
public class HelloClient {
public static void main(String[] args) throws MalformedURLException {
String url = "http://127.0.0.1:8080/hessian-demo/hessian/helloServer";
HessianProxyFactory factory = new HessianProxyFactory();
Ihello basic = (Ihello) factory.create(Ihello.class, url);
System.out.println(basic.invokeSay("xxx"));
}
}

启动服务端,直接运行Client,即可调用服务端的hessian服务


2. 学习Hessian实现

1
2
3
4
5
6
<bean id="helloService" class="com.example.server.HelloServer" />
<bean name="/helloServer"
class="org.springframework.remoting.caucho.HessianServiceExporter">
<property name="service" ref="helloService" />
<property name="serviceInterface" value="com.example.intf.Ihello" />
</bean>

服务端主要通过HessianServiceExporter来作为入口

注入了2个属性,一个接口,一个实现类

HessianServiceExporter.java

HessianServiceExporter extends HessianExporter implements HttpRequestHandler

HessianServiceExporter 继承了一个父类和一个接口

HttpRequestHandler.java

  • HttpRequestHandler#handleRequest(request,response) 用来处理http请求,和servlet类似

HessianExporter.java

HessianExporter extends RemoteExporter implements InitializingBean
  • RemoteExporter.java
    这个类中有下面两个属性,spring中配置的属性,就是通过这个类来实现了注入
    private Object service;
    private Class serviceInterface;

  • InitializingBean.java 接口中只有一个方法
    void afterPropertiesSet();
    这个方法会在spring为bean注入属性后运行

HessianExporter#afterPropertiesSet() 方法主要做了一件事,就是创建了一个HessianSkeleton对象,这个对象就包含了接口和实现类的信息

到这里脉络已经很清晰了,客户端调用服务端的时候,spring将请求转到具体的HttpRequestHandler的bean,调用handleRequest(request,response)方法

HessianServiceExporter Bean中此时已经包含了HessianSkeleton对象

再调用RemoteExporter#doInvoke(HessianSkeleton skeleton, InputStream inputStream, OutputStream outputStream)方法

这个方法会判断Hession的版本号等信息

再调用 HessianSkeleton#invoke(InputStream is, OutputStream os,SerializerFactory serializerFactory)方法

这一步会将输入流和输出流 通过serializerFactory序列化工厂,改为hession自己的流对象, 判断hession头信息合法之后,

再调用invoke(Object service,AbstractHessianInput in,AbstractHessianOutput out)这个方法,此时service参数就已经是我们注入的实现类了,这里面再从输入流里读取要调用的方面名称,参数信息,然后使用java反射包中的Method类来调用result = method.invoke(service, values);

最后把返回信息写入输出流。

调用结束。


从这里可以看到,spring提供了很多实用的接口,比如HttpRequestHandlerInitializingBean,通过这些接口,能非常方便的扩展我们自己的业务和框架。