笔者, 不玩游戏已经有一个月的时间了. 昨天偶然发现大家都在玩吃鸡, 于是好奇心作祟, 昨个不知不觉就到了 5 点多. 笔者现在的电脑配置是 10 年前的, 现在最大的期待是能够有一台配置高, 外观漂亮的电脑. 好了, 每天闲扯一下其实很开心, 也主要是现在的游戏大都是 3D 体验感的, 笔者晕 3D 渲染(配置低的电脑更明显), 没办法啊. 好了废话不多说了, 现在我们实现一种跨 web 网站的数据推送技术: 从当前的 Web 网站生成一个数据文件包, 然后将该数据文件包推送到另一个 Web 网站中, 实现网站展现效果的实时推送. 对此, 笔者尝试使用 Hessian 解决跨 Web 服务进行服务器间的数据推送.
总结一下 hessian:
1, 相比 WebService,Hessian 更简单, 快捷.
2, 采用的是二进制 RPC 协议
RPC 是指远程过程调用协议, 因为采用的是二进制协议, 所以它很适合于发送二进制数据.
3, 对象必须进行序列化
由于使用二进制 RPC 协议传输数据, 对象必须进行序列化, 实现 Serializable 接口
4, 通过 Hessian 本身提供的 API 来发起请求.
5 ,Hessian 通过其自定义的串行化机制将请求信息进行序列化, 产生二进制流.
6,Hessian 基于 Http 协议进行传输.
7, 响应端根据 Hessian 提供的 API 来接收请求.
8,Hessian 根据其私有的串行化机制来将请求信息进行反序列化, 传递给使用者时已是相应的请求信息对象了.
9 , 处理完毕后直接返回, hessian 将结果对象进行序列化, 传输至调用端.
调用端通过 HessianProxyFactory 的 create 方法就是创建接口的代理类, 该类实现了接口, JDK 的 proxy 类会自动用 InvocationHandler 的实现类 (该类在 Hessian 中表现为 HessianProxy ) 的 invoke 方法体来填充所生成代理类的方法体.
Hessian 的这个远程过程调用, 完全使用动态代理来实现的.
除去 spring 对其的封装, 调用端主要是通过 HessianProxyFactory 的 create 方法就是创建接口的代理类, 该类实现了接口, JDK 的 proxy 类会自动用 InvocationHandler 的实现类 (该类在 Hessian 中表现为 HessianProxy ) 的 invoke 方法体来填充所生成代理类的方法体.
调用端系统启动时:
根据 serviceUrl 和 serviceInterface 创建代理.
HessianProxyFactoryBean 类
HessianClientInterceptor 类
createHessianProxy(HessianProxyFactory proxyFactory)
HessianProxyFactory 类
public Object create(Class api, String urlName)
调用端调用 hessian 服务时:
HessianProxy 类的 invoke(Object proxy, Method method, Object []args) 方法
- String methodName = method.getName();// 取得方法名
- Object value = args[0]; // 取得传入参数
- conn = sendRequest(mangleName, args) ; // 通过该方法和服务器端取得连接
- httpConn = (HttpURLConnection) conn;
- code = httpConn.getResponseCode(); // 发出请求
- // 等待被调用端返回相应............
- is = conn.getInputStream();
- Object value = in.readObject(method.getReturnType()); // 取得返回值
HessianProxy 类的 URLConnection sendRequest(String methodName, Object []args) 方法:
- URLConnection conn = _factory.openConnection(_url); // 创建 URLConnection
- OutputStream os = conn.getOutputStream();
- AbstractHessianOutput out = _factory.getHessianOutput(os); // 封装为 hessian 自己的输入输出 API
- out.call(methodName, args);
- return conn;
被调用端接收请求并处理请求
被调用端截获相应请求交给:
org.springframework.remoting.caucho.HessianServiceExporter
具体处理步骤如下:
a) HessianServiceExporter 类
(HessianExporter) invoke(request.getInputStream(), response.getOutputStream());
b) HessianExporter 类
(Hessian2SkeletonInvoker) this.skeletonInvoker.invoke(inputStream, outputStream);
c) Hessian2SkeletonInvoker 类
将输入输出封转化为转化为 Hessian 特有的 Hessian2Input 和 Hessian2Output
- Hessian2Input in = new Hessian2Input(isToUse);
- in.setSerializerFactory(this.serializerFactory);
- AbstractHessianOutput out = null;
- int major = in.read();
- int minor = in.read();
- out = new Hessian2Output(osToUse);
- out = new HessianOutput(osToUse);
- out.setSerializerFactory(this.serializerFactory);
- (HessianSkeleton) this.skeleton.invoke(in, out);
d) HessianSkeleton 类
读取方法名
- String methodName = in.readMethod();
- Method method = getMethod(methodName);
读取方法参数
- Class []args = method.getParameterTypes();
- Object []values = new Object[args.length];
执行相应方法并取得结果
result = method.invoke(service, values);
结果写入到输出流
out.writeObject(result);
总结: 由上面源码分析可知, 被调用端接收处理请求都是通过 hessian 自己的 API . 输入输出流都要封装为 hessian 自己的 Hessian2Input 和 Hessian2Output
笔者一直坚信, 简单代码迭代出复杂功能.
下篇继续, 实地过程中的 hessian, 跨 Web 服务的数据推送.
参考资料Hessian 百度百科
来源: http://www.bubuko.com/infodetail-2729544.html