Hessian和Burlap是caucho公司提供的开源协议,基于HTTP传输,服务端不用开防火墙端口。协议的规范公开,可以用于任意语言。
相比于常用的RPC协议WebService来说,hessian更加简单高效,速度更快,只需要简单的配置即可,无需生成任何类。相对于RMI
来说,hessian支持多种语言和平台,速度也不逊于前者。相对于ICE,hessian是基于http协议,可以穿透防火墙,无需配置相关
设置。因为它是一个Servlet,底层性的工作,比如 输入输出流、并发、日志等事情都可以交给Tomcat、Resin,也便于横向扩容。
不过在使用中发现hessian框架本身也有自己的劣势,比如缺乏安全机制,缺乏超时设置等等。在pop订单中心搭建的过程中,
也参考了网上一些解决方案,在hessian和spring原有的类上面做了扩展,加入了token验证,客户端超时时间配置和最大线程数
限制。配置方式如下:
1 2 3 4 5 6 7 8 9 10 11 12 | <bean id="offlineOrderServiceClient" class="com.tmaic.util.MyHessianProxyFactoryBean"> <property name="serviceUrl" value="http://127.0.0.1/hessian/helloHessian"/> <property name="serviceInterface" value="com.tmaic.service.ShareWordService"/> <property name="overloadEnabled" value="true"/> <property name="connectTimeOut" value="30000"/> <property name="readTimeOut" value="30000"/> <property name="poolMaxSize" value="30"/> <property name="token" value="123456"/> </bean> |
MyHessianProxyFactoryBean 类是继承自HessianProxyFactoryBean,通过spring注入可以方便的
在接入hessian接口时候根据自身接口的需求动态配置参数,connectTimeOut和readTimeOut 限制了最大
超时时间,poolMaxSize 限制了该客户端最大的线程数,token 则是对客户端的安全校验密钥。
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 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 | public class MyHessianProxyFactoryBean extends HessianProxyFactoryBean{ private int readTimeOut = 500; private int connectTimeOut = 30000; private int poolMaxSize = 20; private ReentrantLock lock = new ReentrantLock(); private Condition condition = lock.newCondition(); private AtomicInteger invokeCount = new AtomicInteger(0); private String token; public int getReadTimeOut() { return readTimeOut; } public void setReadTimeOut(int readTimeOut) { this.readTimeOut = readTimeOut; } public int getConnectTimeOut() { return connectTimeOut; } public void setConnectTimeOut(int connectTimeOut) { this.connectTimeOut = connectTimeOut; } public int getPoolMaxSize() { return poolMaxSize; } public void setPoolMaxSize(int poolMaxSize) { this.poolMaxSize = poolMaxSize; } public void setToken(String token) { this.token = token; } @Override public void prepare() throws RemoteLookupFailureException { MyHessianProxyFactory proxyFactory = new MyHessianProxyFactory(); if(this.readTimeOut >0){ proxyFactory.setReadTimeOut(this.readTimeOut); } if(this.connectTimeOut >0){ proxyFactory.setConnectTimeOut(this.connectTimeOut); } if(StringUtils.isNotBlank(token)){ proxyFactory.setToken(token); } this.setProxyFactory(proxyFactory); super.prepare(); } @Override public Object invoke(MethodInvocation invocation) throws Throwable { this.lock.lock(); try{ if(invokeCount.get() > this.poolMaxSize){ System.out.println("invokeCount:"+invokeCount.get()); condition.await(this.readTimeOut, TimeUnit.MILLISECONDS); } if (invokeCount.get() > this.poolMaxSize) { throw new IOException("wait hessian pool timeout: poolSize:" + this.poolMaxSize + ", timeout:" + this.readTimeOut +", no="+invokeCount.get()); } this.invokeCount.incrementAndGet(); }finally { this.lock.unlock(); } Object o = null; try{ o=super.invoke(invocation); }finally { this.lock.lock(); try{ this.invokeCount.decrementAndGet(); condition.signal(); }finally { this.lock.unlock(); } } return o; } } |
MyHessianProxyFactory
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 41 42 43 44 | public class MyHessianProxyFactory extends HessianProxyFactory{ private int connectTimeOut = 30000; private int readTimeOut = 30000; private String token; public int getConnectTimeOut() { return connectTimeOut; } public void setConnectTimeOut(int connectTimeOut) { this.connectTimeOut = connectTimeOut; } public int getReadTimeOut() { return readTimeOut; } public void setReadTimeOut(int readTimeOut) { this.readTimeOut = readTimeOut; } public String getToken() { return token; } public void setToken(String token) { this.token = token; } protected URLConnection openConnection(URL url) throws IOException { URLConnection conn = super.openConnection(url); if (this.connectTimeOut > 0) { conn.setConnectTimeout(this.connectTimeOut); } if (this.readTimeOut > 0) { conn.setReadTimeout(this.readTimeOut); } if(token!=null && !"".equals(token)){ conn.setRequestProperty("AUTH",token); } return conn; } } |
MyHessianServiceExporter
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 | public class MyHessianServiceExporter extends HessianServiceExporter{ private String token; private final static org.apache.log4j.Logger logger = org.apache.log4j.Logger.getLogger(MyHessianServiceExporter.class); @Override public void handleRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String auth = request.getHeader("AUTH"); if(!checkTokenHeader(auth)){ logger.error("token is error!"); return; } super.handleRequest(request, response); } private boolean checkTokenHeader(String clientToken){ if (StringUtils.isBlank(clientToken)) { return false; } if (StringUtils.isBlank(token)) { return false; } return token.equals(clientToken); } //get set public void setToken(String token) { this.token = token; } } |