Hessian入门实战

摘要

Hessian 官网:http://hessian.caucho.com/

Hessian是由Caocho公司发布的一个轻量级的二进制协议远程调用实现方案,Hessian也是基于HTTP协议的。

Hessian支持很多种语言,例如Java,Flash/Flex,python,c++,.net/c#,D,Erlang,PHP,Ruby,Object C等。

Hessian是一个轻量级的remoting onhttp工具,使用简单的方法提供了RMI的功能,相比WebService,Hessian更简单、快捷。采用的是二进制RPC协议,因为采用了二进制协议,所以它很适合于发送二进制数据,而不需要引入其它附件去扩展它的协议,Hessian主要作面向对象的消息通信。

协议解析

Hessian 协议: http://hessian.caucho.com/doc/hessian-serialization.html

参考另一篇博文Hessian协议解析

使用SpringBoot的Hello Wrold

Demo:https://github.com/liuhailin/Learning/tree/master/studyHessian

工作原理

前面我们知道Hessian是基于Http协议的,通过建立http连接发送数据,RMI的原理自然用到动态代理机制。

客户端默认用的是jdk的动态代理,类HessianProxyFactory会创建一个代理对象,最终会执行HessianProxy的invoke方法。invoke中发送http请求。

服务端通过注册HessianServlet实现request映射。配置web.xml即可。

如果集成Spring的话,Spring提供服务端的HessianServiceExporter类,来发布一个服务。

客户端通过注册HessianProxyFactoryBeanBean来创建动态代理,用Spring提供的类,我们很容易替换掉动态代理的实现,可以用性能更好的cglib。

可查看Demo的用法。

注意事项

对象必须实现Serializable接口,复杂对象中,必须全部实现序列化。

如何自动暴露Hessian服务

在Demo的server模块中,要注册一个服务需要添加下面代码:

1
2
3
4
5
6
7
@Bean(name = "/hello")
public HessianServiceExporter hessianServiceExporter() {
HessianServiceExporter exporter = new HessianServiceExporter();
exporter.setService(helloHession);
exporter.setServiceInterface(IHelloHession.class);
return exporter;
}

上面注册了一个/hello的rest http接口服务,并指定接口和实现类。但是问题是,每当我们发布服务都需要添加代码。能否自动发布呢?当然是可以的。只要自动的生成Bean名字不同的HessianServiceExporter就可以了。

可以有几种实现:

  • service实现类上使用了Spring提供的@service,会自动注册到容器中,那么我们只需要初始化HessianServicesExporter就可以,可以扩展BeanPostProcessor接口。
  • 如果不实用@service注解,自定义注解,并扩展ClassPathBeanDefinitionScanner自定义scanner扫描服务类,扩展BeanDefinitionParserNamespaceHandlerSupport ,注册扫描器,然后扩展BeanFactoryPostProcessor注册到容器,注册服务的同时,把HessianServiceExporter一起注册就可以。
  • 在自定义注解上使用@service注解,然后扩展BeanFactoryPostProcessor ,获取getBeanNamesForAnnotation得到所有BeanName遍历,注册服务即可。

Hessian安全考虑

超时时间

在Spring提供的HessianProxyFactoryBean类中,有接口可以设置ReadTimeOut和ConnectionTimeOut,HessianProxyFactoryBean是一个FactoryBean,产生一个代理对象。

我们重写在afterPropertiesSet或者prepare并设置我们自己的HessianProxyFactory。只要设置HessianProxyFactory的时间,HessianConnectionFactory 的实现类HessianURLConnectionFactory在调用open的时候会加上。

Base Authorization

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34

/**
* @author Liu Hailin
* @create 2017-11-22 上午11:28
**/

@Setter(AccessLevel.PUBLIC)
@Slf4j
public class HessianBagProxyFactoryBean extends HessianProxyFactoryBean {

private int readTimeOut = 10000;
private int connectionTimeOut = 30000;

@Override
public void prepare() throws RemoteLookupFailureException {

HessianProxyFactory proxyFactory = new HessianProxyFactory();

proxyFactory.setReadTimeout( readTimeOut );
proxyFactory.setConnectTimeout( connectionTimeOut );
proxyFactory.setUser( "liuhailin" );
proxyFactory.setPassword( "liuhailin" );

HessianBagURLConnectionFactory urlConnectionFactory = new HessianBagURLConnectionFactory();

urlConnectionFactory.setHessianProxyFactory( proxyFactory );

proxyFactory.setConnectionFactory( urlConnectionFactory );

setProxyFactory( proxyFactory );

super.prepare();
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
/**
* @author Liu Hailin
* @create 2017-11-22 下午2:16
**/
@Slf4j
public class HessianBagServiceExporter extends HessianServiceExporter {

private String auth;

@Override
public void handleRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {

if (!checkSecurity( request )) {
PrintWriter writer = response.getWriter();
writer.write( "error" );
writer.flush();
return;
}

super.handleRequest( request, response );
}

private boolean checkSecurity(HttpServletRequest request) {

String from = request.getHeader( "from" );

String authorization = request.getHeader( "Authorization" );
if (StringUtils.isNotBlank( auth ) && StringUtils.isNotBlank( authorization )) {
String authCode = StringUtils.substringAfter( authorization, " " );
String expectCode = Base64Utils.encodeToString( auth.getBytes() );

if (!authCode.equals( expectCode )) {
return false;
}
log.info( "Request from is:{}", from );
}
return true;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/**
* @author Liu Hailin
* @create 2017-11-22 下午2:09
**/
public class HessianBagURLConnectionFactory extends HessianURLConnectionFactory {


@Override
public HessianConnection open(URL url) throws IOException {

HessianConnection connection = super.open( url );

//可以加入token
connection.addHeader( "from","100.0.0.1" );

return connection;
}
}
数据加密

Hessian的com.caucho.hessian.security包下面有两个类X509Encryption和X509Signature,一个是用来加密解密的,一个是用来签名认证的。

这里我们用X509Encryption是对称加密算法。需要提供privateKey。

代码参考:https://github.com/liuhailin/HessianBag

参考文档:

https://github.com/xwjie/HessianDemo

http://blog.csdn.net/bb188641864/article/details/51828748

http://gordian.iteye.com/blog/2249837

http://zwustudy.iteye.com/blog/1679850

坚持技术分享,您的支持将鼓励我继续创作!