Hessian 源码简单分析

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 是必须是一个接口,也就是服务,值必须是一个接口的全路径FQN
service 是具体的实现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, 它仅仅是在测试环境中使用。

posted on 2017-08-15 13:10 CanntBelieve 阅读(...) 评论(...) 编辑 收藏

转载于:https://www.cnblogs.com/FlyAway2013/p/7364576.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/371492.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Java开发人员应该知道的三件事

对于那些长期关注JavaOne 2012会议的读者来说&#xff0c;这是一篇有趣的文章。 我最近对Java冠军Heinz Kabutz的采访引起了我的注意&#xff1b; 包括他的Java内存难题程序&#xff0c;从Java内存管理的角度来看&#xff0c;这很有启发性。 采访中有一个特别的部分吸引了我的注…

android怎么垂直居中且靠右,placeholder 靠右垂直居中/位置兼容

1.input输入框文字靠右垂直居中。2.placehoder提示同样靠右垂直居中。( placeholder是HTML5 input的新属性&#xff0c;英文意思是占位符&#xff0c;它一般表示input输入框的默认提示值。)css代码input {text-align: right;font-size:0.3rem;width:100%;height:0.78rem;line-…

Python-Matplotlib 18 注释

Python-Matplotlib 18 注释 EG1: import numpy as np import matplotlib.pyplot as plty np.arange(-5, 6,1) plt.plot(y, y*y) plt.annotate(Annotate , xy(0,1) , xytext(0,5) ,arrowpropsdict(facecolorr , frac0.2 ))plt.show()转载于:https://www.cnblogs.com/zsr0401/p/…

while和for循环

循环结构图&#xff1a; 循环结构主要分为两种&#xff1a;有while和for两种循环&#xff0c;while又分为do{...}while和while{...},do...while表示先执行后判断&#xff0c;而while循坏表示先判断后执行&#xff0c;如果循环条件都不满足的情况下&#xff0c;do...while至少执…

通过beforeClass和afterClass设置增强Spring Test Framework

如何允许实例方法作为JUnit BeforeClass行为运行 JUnit允许您在所有测试方法调用之前和之后一次在类级别上设置方法。 但是&#xff0c;通过有意设计&#xff0c;他们将其限制为仅使用BeforeClass和AfterClass批注的静态方法。 例如&#xff0c;此简单的演示显示了典型的Junit设…

华为鸿蒙出来正当时,关于华为鸿蒙操作系统,中兴率先表态

原标题&#xff1a;关于华为鸿蒙操作系统&#xff0c;中兴率先表态 来源&#xff1a;科技数码迷进入2021年之后中兴这个品牌的存在感越来越强了&#xff0c;并且还学会了借势营销。每当国内智能手机领域有大事之时总会看到中兴或红魔手机的身影。这说明在5G过渡期中兴要借个机会…

条件变量(Condition Variable)详解

转载于&#xff1a;http://blog.csdn.net/erickhuang1989/article/details/8754357 条件变量(Condtion Variable)是在多线程程序中用来实现“等待->唤醒”逻辑常用的方法。举个简单的例子&#xff0c;应用程序A中包含两个线程t1和t2。t1需要在bool变量test_cond为true时才能…

C++中的深拷贝和浅拷贝 QT中的深拷贝,浅拷贝和隐式共享

下面是C中定义的深&#xff0c;浅拷贝 当用一个已初始化过了的自定义类类型对象去初始化另一个新构造的对象的时候&#xff0c;拷贝构造函数就会被自动调用。也就是说&#xff0c;当类的对象需要拷贝时&#xff0c;拷贝构造函数将会被调用。以下情况都会调用拷贝构造函数&#…

使用PowerMock模拟构造函数

我认为&#xff0c;依赖项注入的主要好处之一是可以将模拟和/或存根对象注入代码中&#xff0c;以提高可测试性&#xff0c;增加测试覆盖率并编写更好&#xff0c;更有意义的测试。 但是&#xff0c;有时候您会遇到一些不使用依赖注入的传统代码&#xff0c;而是通过组合而不是…

Brackets (区间DP)

个人心得&#xff1a;今天就做了这些区间DP&#xff0c;这一题开始想用最长子序列那些套路的&#xff0c;后面发现不满足无后效性的问题&#xff0c;即&#xff08;&#xff0c;&#xff09;的配对 对结果有一定的影响&#xff0c;后面想着就用上一题的思想就慢慢的从小一步一步…

android生成aar无效,android studio生成aar包并在其他工程引用aar包的方法

1.aar包是android studio下打包android工程中src、res、lib后生成的aar文件&#xff0c;aar包导入其他android studio 工程后&#xff0c;其他工程可以方便引用源码和资源文件2.生成aar包步骤&#xff1a;①.用android studio打开一个工程&#xff0c;然后新建一个Module&#…

《剑指offer》— JavaScript(3)从尾到头打印链表

从尾到头打印链表 题目描述 输入一个链表&#xff0c;从尾到头打印链表每个节点的值。 实现代码 /*function ListNode(x){this.val x;this.next null; }*/ function printListFromTailToHead(head) {var res[];while(head){res.unshift(head.val);headhead.next;}return res;…

JUnit测试Spring Service和DAO(带有内存数据库)

这篇文章描述了如何为Spring Web Application的Services和DAO实现JUnit测试。 它建立在Spring MVC-Service-DAO-Persistence Architecture Example的基础上 。 从Github的Spring-Web-JPA-Testing目录中可以找到该示例。 提醒 测试装置 –固定状态&#xff0c;用作运行测试的基…

c# 正则获取html标签内容,c# – 使用正则表达式在多个HTML标记之间获取文本

使用正则表达式,我希望能够在多个DIV标记之间获取文本.例如,以下内容&#xff1a;first html taganother tag输出&#xff1a;first html taganother tag我使用的正则表达式模式只匹配我的最后一个div标签并错过了第一个.码&#xff1a;static void Main(string[] args){string…

Android之外部存储(SD卡)

*手机的外部存储空间&#xff0c;这个我们可以理解成电脑的外接移动硬盘&#xff0c;U盘也行。所有的Android设备都有两个文件存储区域&#xff1a;“内部”和“外部”存储器。这两个名称来自早期的Android&#xff0c;当时大多数设备都提供内置的固定的内存&#xff08;内置存…

通用并发对象池

在本文中&#xff0c;我们将介绍如何在Java中创建对象池。 近年来&#xff0c;JVM的性能成倍增加&#xff0c;大多数类型的对象几乎都变得多余&#xff0c;从而提高了对象池的性能。 从本质上讲&#xff0c;对象的创建不再像以前那样昂贵。 但是&#xff0c;有些对象在创建时肯…

圆周率的代码表示,以及对其的理解。

转载的简书&#xff0c;for 记录以及记忆。 http://www.jianshu.com/p/7208e4a58310 Thanks again&#xff01; 转载于:https://www.cnblogs.com/xiapeng0701/p/7538281.html

华为NOVa8Pr0是用鸿蒙系统吗,华为Nova8即将发布,采用麒麟芯片,高端平板适配鸿蒙系统...

大家好&#xff0c;我是老孙自从华为Mate40系列发布后&#xff0c;下一步新机动态备受外界关注&#xff0c;华为究竟会不会继续生产手机呢&#xff1f;答案是肯定&#xff0c;华为Nova8系列将于本月发布&#xff0c;华为P50系列也在积极筹备&#xff0c;而且都少不了麒麟芯片&a…

使用路标的Scala和Java的Twitter REST API

如果您已阅读此博客上的其他文章&#xff0c;您可能会知道我喜欢创建各种数据集的可视化。 我刚刚开始一个小项目&#xff0c;在这里我想可视化来自Twitter的一些数据。 为此&#xff0c;我想直接从Twitter检索有关关注者的信息和个人资料信息。 我实际上开始寻找一组所有推特帐…

大话设计模式读书笔记--11.抽象工厂模式

定义 抽象工厂模式定义: 提供一个创建一系列相关或相关依赖对象的接口,而无需指定他们具体的类 抽象工厂模式通常是用于创建一族产品&#xff0c;并且这族产品分不同的等级&#xff1b;不同的具体工厂类生产不同等级的一族产品 比如下图(来源于网络) 两厢车和三厢车称为两个不同…