Hessian 源码简单分析
Hessian 是一个rpc框架, 我们需要先写一个服务端, 然后在客户端远程的调用它即可。
服务端:
服务端通常和spring 做集成。
首先写一个接口:
public interface HelloService { void sayHello(String name); }
然后一个实现,实现使用@Service("helloService") 实现spring bean注册。
@Service("helloService") public class HelloServiceImpl implements HelloService { @Override public void sayHello(String name) { System.out.println("Hello " + name + "!"); } } spring xml配置中,通过org.springframework.remoting.caucho.HessianServiceExporter 完成服务的暴露:
<!-- Name保持与web.xml中的一致,web.xml下文中描述 --><bean name="HelloServiceExporter" class="org.springframework.remoting.caucho.HessianServiceExporter"> <!-- service的ref与HelloServiceImpl中@Service中配置的一致 --> <property name="service" ref="helloService" /> <!-- 接口的路径 --> <property name="serviceInterface" value="hessian.HelloService" /></bean>
web.xml 的关键配置:
<servlet> <!-- servlet-name保持与spring-hessian.xml中一致 --> <servlet-name>HelloServiceExporter</servlet-name> <servlet-class>org.springframework.web.context.support.HttpRequestHandlerServlet</servlet-class></servlet><servlet-mapping> <servlet-name>HelloServiceExporter</servlet-name> <url-pattern>/HelloService</url-pattern></servlet-mapping>
HessianServiceExporter 有两个关键的属性: serviceInterface 和 service serviceInterface 是必须是一个接口,也就是服务,值必须是一个接口的全路径FQNservice 是具体的实现bean,是一个实例的引用
HttpRequestHandlerServlet extends HttpServlet
HttpRequestHandlerServlet 的关键代码是:
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { LocaleContextHolder.setLocale(request.getLocale()); try { this.target.handleRequest(request, response); } catch (HttpRequestMethodNotSupportedException var8) { String[] supportedMethods = var8.getSupportedMethods(); if (supportedMethods != null) { response.setHeader("Allow", StringUtils.arrayToDelimitedString(supportedMethods, ", ")); } response.sendError(405, var8.getMessage()); } finally { LocaleContextHolder.resetLocaleContext(); } } 其实就是调用了 HessianServiceExporter 的handler 方法,HessianServiceExporter 的关键代码是:
public void handleRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { if (!"POST".equals(request.getMethod())) { throw new HttpRequestMethodNotSupportedException(request.getMethod(), new String[]{"POST"}, "HessianServiceExporter only supports POST requests"); } else { response.setContentType("application/x-hessian"); try { this.invoke(request.getInputStream(), response.getOutputStream()); } catch (Throwable var4) { throw new NestedServletException("Hessian skeleton invocation failed", var4); } }} 代码关系是:
HessianServiceExporter extends HessianExporter implements HttpRequestHandler
HessianExporter extends RemoteExporter implements InitializingBean
HessianExporter has a HessianSkeleton
HessianSkeleton extends AbstractSkeleton
HessianSkeleton 的invoke 方法实现关键的request处理
具体来说:
HessianInput extends AbstractHessianInput
HessianOutput extends AbstractHessianOutput
HessianInput 有提供 readHeader、readMethod、readMethodArgLength、readBytes、readInt、readLong、readString/readDouble/readObject、 readCall、 startCall、completeCall、readReply、startReply、completeReply 等方法
HessianOutput 有writeBytes Int long , Double,String, Object, writeReply 等方法
req 获取 InputStream, res 获取OutputStream。
HessianInput 从 req 中读取 方法,参数, 然后method 反射调用 service, 然后通过 HessianOutput 写回结果
in.completeCall();out.writeReply(result); // 发送处理结果到 远程客户端out.close(); 这样, 就完成了服务端的编写,看起来还是比较简单的。
客户端:因为Hessian服务端暴露的服务实际上是一个基于http实现通信的。 故我们需要通过http 调用 Hessian。 客户端可以是一个web应用,也可以是一个简单的main: 方式1,通过HessianProxyFactory:
public static void main(String[] args) { try { String url = "http://localhost:8080/HelloService"; HessianProxyFactory factory = new HessianProxyFactory(); HelloService helloService = (HelloService) factory.create( HelloService.class, url); helloService.sayHello("张三"); } catch (Exception e) { e.printStackTrace(); }}稍微查看一下源码,我们就会发现:
HessianProxy implements InvocationHandler, Serializable 可见 hessian 是使用jdk 动态代理实现的, 故我们需要一个接口
HessianURLConnection extends AbstractHessianConnection implements HessianConnection
HessianURLConnection 有一个 java.net.URLConnection , 可见Hessian 的通信主要就是通过http, 具体是 URLConnection实现的。
HessianProxy has a HessianProxyFactory
HessianProxyFactory has a HessianConnectionFactory
HessianProxyFactory 用来获取conn: conn = this._factory.getConnectionFactory().open(this._url);
HessianProxy relate to HessianConnection
具体来说是这样的:
create 返回的是一个代理, return Proxy.newProxyInstance(loader, new Class[]{api, HessianRemoteObject.class}, handler);
HessianProxy 的invoke 是关键:
sendRequest 方法
os = conn.getOutputStream(); 通过conn 返回OutputStream
OutputStream os 强制转换为 AbstractHessianOutput, 然后
out.call(methodName, args); // 发送数据到 远程服务端
out.flush();
conn.sendRequest(); // 返回一个statusMessage
is = httpConn.getInputStream(); // 通过conn获取InputStream,
conn = this.sendRequest(mangleName, args);
is = conn.getInputStream(); // 通过sendRequest发送完数据后, 就可以通过conn 获取远程的返回的数据了。
InputStream的is 转换为 AbstractHessianInput 后, 然后就可以 readObject
value = in.readObject(method.getReturnType()); // readObject 最终返回了 远程调用的结果。 至此,单次 rpc 结束
方式2,通过HessianProxyFactoryBean:
public static void main(String[] args) { ClassPathXmlApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext("spring-servlet.xml"); HelloService ser = (HelloService) classPathXmlApplicationContext.getBean("testHessianService"); ser.sayHello("lk AA");} 其实也就是把前面的HessianProxyFactory 集成到了spring,封装成了bean
HessianProxy implements InvocationHandler, Serializable 可见 hessian 是使用jdk 动态代理实现的, 故我们需要一个接口
HessianURLConnection extends AbstractHessianConnection implements HessianConnection
HessianProxyFactoryBean extends HessianClientInterceptor implements FactoryBean<Object>
HessianClientInterceptor extends UrlBasedRemoteAccessor implements MethodInterceptor
HessianClientInterceptor has a HessianProxyFactory
HessianClientInterceptor 定义hessianProxy:有一个属性: private Class serviceInterface;
serviceInterface 定义serviceInterface:有一个属性: private Class serviceInterface;
UrlBasedRemoteAccessor 定义serviceUrl:有一个属性: private String serviceUrl;
hessianProxy 是通过proxyFactory(也就是HessianProxyFactory)创建, 可见, HessianProxyFactoryBean 还是通过HessianProxyFactory来完成的主要工作的。
简单说,其实就是 spring 通过反射的调用proxyFactory 的远程方法。
当然,实际使用的时候, 我们不会使用 ClassPathXmlApplicationContext, 它仅仅是在测试环境中使用。
转载于:https://www.cnblogs.com/FlyAway2013/p/7364576.html
Hessian 源码简单分析相关推荐
- poco源码简单分析
自动化工具poco源码简单分析 Airtest简介 Airtest是网易游戏开源的一款UI自动化测试项目,目前处于公开测试阶段,该项目分为AirtestIDE.Airtest.Poco.Testlab ...
- FFmpeg的HEVC解码器源码简单分析:概述
===================================================== HEVC源码分析文章列表: [解码 -libavcodec HEVC 解码器] FFmpeg ...
- FFmpeg的HEVC解码器源码简单分析:解码器主干部分
===================================================== HEVC源码分析文章列表: [解码 -libavcodec HEVC 解码器] FFmpeg ...
- JSP 编译和运行过程与JSP源码简单分析
JSP 编译和运行过程与JSP转移源码简单分析 Web容器处理JSP文件请求的执行过程主要包括以下4个部分: 1. 客户端发出Request请求 2. JSP Container 将JSP转译成Ser ...
- 线程的3种实现方式并深入源码简单分析实现原理
前言 本文介绍下线程的3种实现方式并深入源码简单的阐述下原理 三种实现方式 Thread Runnable Callable&Future 深入源码简单刨析 Thread Thread类实现了 ...
- reentrantlock失效了?_ReentrantLock 源码简单分析
JAVA中锁的实现最常见的方式有两种,一种是 synchronized关键字,一种是Lock.实际的开发过程中,要对这两种方式进行取舍. synchronized是基于JVM层面实现的, Lock却是 ...
- ChaLearn Gesture Challenge_3:Approximated gradients源码简单分析
前言 上一篇博文ChaLearn Gesture Challenge_2:examples体验 中简单介绍了CGC官网提供的丰富的sample,本节来简单分下其中的一个sample源码,该sample ...
- Linux·内核源码简单分析
目录 系统总体流程: 各个目录的阅读总结: (一) boot (二)内核初始化init (三)kernel: (四)mm内存管理 (五)文件系统模块fs: 系统总体流程: 系统从boot开始动作,把内 ...
- Enemy源码简单分析
这是这个项目的网页链接,以下是关于enemy源代码的粗略分析. https://github.com/freakanonymous/enemy 弗兰克,是一个全职的恶意代码工程师,会不定期更新enem ...
最新文章
- php设置accept,PHP或htaccess通过Accept-Language重写URL?
- php开发流程 restful,PhpBoot 入门(一) 快速开发 RESTful 接口
- Python笔记:0
- MySQL5.7重置root密码
- Java基础6:代码块与代码加载顺序
- 多媒体计算机软件系统课件,《多媒体计算机系统》PPT课件.ppt
- spring cloud alibaba全家桶之nacos
- linux桌面图标恢复,修复桌面白图标的教程
- 伦敦交通局设置较低的速度限制
- python列表索引超出范围 等于啥_Python列表错误,列表索引超出范围
- 关于短信群发的简单实现
- Windows个性化之稀奇古怪三两式(转)
- OpenWrt安装腾讯云DDNS插件
- 用C语言实现一个简单的计算器代码
- w7桌面计算机图标打不开了,桌面图标打不开,教您桌面图标打不开怎么办
- Could not initialize class JDBC.JDBCUtils 已解决
- 苹果设计团队正在经历重大变革:三名核心元老离职
- 历史上的今天:网景浏览器诞生;ENIAC 首席设计师出生;全球首例全机器人手术...
- 【GitHub】在Github主页显示你的个人简历
- esxi 自动给虚拟机打快照(定时快照任务)