基于springmvc的hessian调用原理浅析
一、客户端
1、构造(初始化)
由客户端的配置文件随容器的启动而进行初始化,配置文件如下:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd"> <context:property-placeholder location="classpath:/server.properties" ignore-unresolvable="true"/> <bean id="application"
class="org.springframework.remoting.caucho.HessianProxyFactoryBean">
<property name="serviceUrl">
<value>${app_server_path}</value>
</property>
<property name="serviceInterface">
<value>com.avatarmind.server.service.ApplicationService</value>
</property>
</bean> </beans>
先放张类关系图:

根据spring生命周期可知,容器初始化,会调用InitializingBean的afterPropertiesSet()方法,
而HessianProxyFactoryBean类实现了InitializingBean接口并重写了afterPropertiesSet()方法。
所以主要流程为:
1)、HessianProxyFactoryBean的afterPropertiesSet()
2)、HessianClientInterceptor的afterPropertiesSet()
3)、HessianClientInterceptor的prepare()
4)、HessianClientInterceptor的createHessianProxy(HessianProxyFactory proxyFactory)
5)、HessianProxyFactory的create(Class<?> api, String urlName, ClassLoader loader)
public Object create(Class<?> api, URL url, ClassLoader loader)
{
if (api == null)
throw new NullPointerException("api must not be null for HessianProxyFactory.create()");
InvocationHandler handler = null; handler = new HessianProxy(url, this, api); return Proxy.newProxyInstance(loader,
new Class[] { api,
HessianRemoteObject.class },
handler);
}
整个流程最终就是为服务接口生成代理类。
2、使用接口调用服务
具体的方法调用我就不写了,不知道的可以看我以前写的hessian的基本使用。
由public class HessianProxy implements InvocationHandler, Serializable和构造的第 5)里的代码可知
接口的调用会转到HessianProxy的invoke(Object proxy, Method method, Object []args)方法里。
具体的代码如下,有些细节我也不是很懂,好像就是序列化、发送请求(conn = sendRequest(mangleName, args);)、
反序列化,还有校验和处理其他方法。
public Object invoke(Object proxy, Method method, Object []args)
throws Throwable
{
String mangleName; synchronized (_mangleMap) {
mangleName = _mangleMap.get(method);
} if (mangleName == null) {
String methodName = method.getName();
Class<?> []params = method.getParameterTypes(); // equals and hashCode are special cased
if (methodName.equals("equals")
&& params.length == 1 && params[0].equals(Object.class)) {
Object value = args[0];
if (value == null || ! Proxy.isProxyClass(value.getClass()))
return Boolean.FALSE; Object proxyHandler = Proxy.getInvocationHandler(value); if (! (proxyHandler instanceof HessianProxy))
return Boolean.FALSE; HessianProxy handler = (HessianProxy) proxyHandler; return new Boolean(_url.equals(handler.getURL()));
}
else if (methodName.equals("hashCode") && params.length == 0)
return new Integer(_url.hashCode());
else if (methodName.equals("getHessianType"))
return proxy.getClass().getInterfaces()[0].getName();
else if (methodName.equals("getHessianURL"))
return _url.toString();
else if (methodName.equals("toString") && params.length == 0)
return "HessianProxy[" + _url + "]"; if (! _factory.isOverloadEnabled())
mangleName = method.getName();
else
mangleName = mangleName(method); synchronized (_mangleMap) {
_mangleMap.put(method, mangleName);
}
} InputStream is = null;
HessianConnection conn = null; try {
if (log.isLoggable(Level.FINER))
log.finer("Hessian[" + _url + "] calling " + mangleName);
// 调用服务端
conn = sendRequest(mangleName, args); is = getInputStream(conn); if (log.isLoggable(Level.FINEST)) {
PrintWriter dbg = new PrintWriter(new LogWriter(log));
HessianDebugInputStream dIs
= new HessianDebugInputStream(is, dbg); dIs.startTop2(); is = dIs;
} AbstractHessianInput in; int code = is.read(); if (code == 'H') {
int major = is.read();
int minor = is.read(); in = _factory.getHessian2Input(is); Object value = in.readReply(method.getReturnType()); return value;
}
else if (code == 'r') {
int major = is.read();
int minor = is.read(); in = _factory.getHessianInput(is); in.startReplyBody(); Object value = in.readObject(method.getReturnType()); if (value instanceof InputStream) {
value = new ResultInputStream(conn, is, in, (InputStream) value);
is = null;
conn = null;
}
else
in.completeReply(); return value;
}
else
throw new HessianProtocolException("'" + (char) code + "' is an unknown code");
} catch (HessianProtocolException e) {
throw new HessianRuntimeException(e);
} finally {
try {
if (is != null)
is.close();
} catch (Exception e) {
log.log(Level.FINE, e.toString(), e);
} try {
if (conn != null)
conn.destroy();
} catch (Exception e) {
log.log(Level.FINE, e.toString(), e);
}
}
}
二、服务端
1、构造(初始化)
配置文件:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <!-- app -->
<bean id="applicationServiceImpl" class="com.server.service.impl.ApplicationServiceImpl" /> <!-- 使用HessianServiceExporter 将普通bean导出成Hessian服务 -->
<bean name="/app"
class="org.springframework.remoting.caucho.HessianServiceExporter">
<property name="service" ref="applicationServiceImpl" />
<!-- Hessian服务的接口 -->
<property name="serviceInterface" value="com.server.service.ApplicationService" />
</bean> </beans>
同理:

主要流程:
1)、HessianExporter的afterPropertiesSet()
2)、HessianExporter的prepare()
3)、RemoteExporter的getProxyForService()
流程主要是生成HessianSkeleton类的对象。
因为配置文件的bean的name带 / 符号,所以会被BeanNameUrlHandlerMapping进行映射处理。
2、被调用
由于基于mvc,所以请求会先到DispatcherServlet的doDispatch方法,然后根据路径获取handler,
因此服务的入口为HessianServiceExporter的handleRequest()方法。
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");
} response.setContentType(CONTENT_TYPE_HESSIAN);
try {
// 调用
invoke(request.getInputStream(), response.getOutputStream());
}
catch (Throwable ex) {
throw new NestedServletException("Hessian skeleton invocation failed", ex);
}
}
流程:
1)、HessianServiceExporter的handleRequest()
2)、HessianExporter的invoke(InputStream inputStream, OutputStream outputStream)
3)、HessianExporter的doInvoke(HessianSkeleton skeleton, InputStream inputStream, OutputStream outputStream)
核心代码:skeleton.invoke(in, out);
4)、HessianSkeleton的invoke()
核心代码:result = method.invoke(service, values);
利用反射调用具体的实现方法。中间掺杂着反序列化,校验,序列化的其他方法。
有些地方自己也不是很懂,主要是记录大体的流程,细节后续再细究吧。
基于springmvc的hessian调用原理浅析的更多相关文章
- [转载] 基于Dubbo的Hessian协议实现远程调用
转载自http://shiyanjun.cn/archives/349.html Dubbo基于Hessian实现了自己Hessian协议,可以直接通过配置的Dubbo内置的其他协议,在服务消费方进行 ...
- 基于Dubbo的Hessian协议实现远程调用
Dubbo基于Hessian实现了自己Hessian协议,可以直接通过配置的Dubbo内置的其他协议,在服务消费方进行远程调用,也就是说,服务调用方需要使用Java语言来基于Dubbo调用提供方服务, ...
- Dubbo学习(一) Dubbo原理浅析
一.初入Dubbo Dubbo学习文档: http://dubbo.incubator.apache.org/books/dubbo-user-book/ http://dubbo.incubator ...
- 基于SpringMVC下的Rest服务框架搭建【1、集成Swagger】
基于SpringMVC下的Rest服务框架搭建[1.集成Swagger] 1.需求背景 SpringMVC本身就可以开发出基于rest风格的服务,通过简单的配置,即可快速开发出一个可供客户端调用的re ...
- 沉淀,再出发:docker的原理浅析
沉淀,再出发:docker的原理浅析 一.前言 在我们使用docker的时候,很多情况下我们对于一些概念的理解是停留在名称和用法的地步,如果更进一步理解了docker的本质,我们的技术一定会有质的进步 ...
- 消息队列——ActiveMQ使用及原理浅析
文章目录 引言 正文 一.ActiveMQ是如何产生的? 产生背景 JMS规范 基本概念 JMS体系结构 二.如何使用? 基本功能 消息传递 P2P pub/sub 持久订阅 消息传递的可靠性 事务型 ...
- 老生常谈系列之Aop--Spring Aop原理浅析
老生常谈系列之Aop--Spring Aop原理浅析 概述 上一篇介绍了AspectJ的编译时织入(Complier Time Weaver),其实AspectJ也支持Load Time Weaver ...
- Javascript自执行匿名函数(function() { })()的原理浅析
匿名函数就是没有函数名的函数.这篇文章主要介绍了Javascript自执行匿名函数(function() { })()的原理浅析的相关资料,需要的朋友可以参考下 函数是JavaScript中最灵活的一 ...
- JAVA WEB快速入门之从编写一个基于SpringMVC框架的网站了解Maven、SpringMVC、SpringJDBC
接上篇<JAVA WEB快速入门之通过一个简单的Spring项目了解Spring的核心(AOP.IOC)>,了解了Spring的核心(AOP.IOC)后,我们再来学习与实践Maven.Sp ...
随机推荐
- 分布式版本控制git常见问题之gitignore冲突
所见即所得,建议大家用可视化的SourceTree专为git打造的,非常好用,废话不多说了. 原因是有人提交了.gitignore里面的内容,所以和本地的不一样,这样就有问题,那么pull都不可以,所 ...
- 面向对象(java菜鸟的课堂笔记)
类:相同的东西放在一起 分为属性和动作: 把一组或多组事物相同的特性的描述==>类 属性和动作被称为成员: //声明类的属性信息 public class **{ String name: ...
- nodeJS之TCP模块net
前面的话 TCP服务在网络应用中十分常见,目前大多数的应用都是基于TCP搭建而成的.net模块提供了一个异步网络包装器,用于TCP网络编程,它包含了创建服务器和客户端的方法.本文将详细介绍nodeJS ...
- java基础(四章)
一. switch结构(开关语句)的语法 switch(表达式 ){ ------- [dream1]类型为int.char case 常量1 : ---------[ ...
- Canvas学习系列二:Canvas的坐标系统
上一章内容中我们对canvas元素有了一个初步的认识,在接下来的章节中我们会慢慢学习canvas中图形的绘制:但是在绘制之前我们先来看看canvas中的坐标系统,因为这样我们才能知道绘制的图形放在什么 ...
- Myeclipse快捷键组合
------------------------------------- MyEclipse 快捷键1(CTRL) ------------------------------------- Ctr ...
- 【Python3之面向对象的程序设计】
一.面向对象的程序设计的由来 1.第一阶段:面向机器,1940年以前 最早的程序设计都是采用机器语言来编写的,直接使用二进制码来表示机器能够识别和执行的指令和数据. 简单来说,就是直接编写 0 和 1 ...
- ThreadLocal来管理事务
ThreadLocal (扩展) 1 ThreadLocal API ThreadLocal类只有三个方法: l void set(T value):保存值: l T get():获取值: l ...
- easygen通用代码生成框架[开源]
什么东东 用过mybatis的同学都知道,手工写mapper和xml是一件很痛苦的事儿,幸好官方提供了Mybatis-Generator,但是这家伙生成的东西不开放不方便修改,而且项目中的代码生成需求 ...
- 前端开发规范:命名规范、html 规范、css 规范、js 规范
上周小组的培训内容是代码可读性艺术,主要分享如何命名.如何优化代码排版,如何写好的注释.我们都知道写出优雅的代码是成为大牛的必经之路. 下面感谢一位前端开发小伙伴总结的前端开发规范,通过学习相关开发规 ...