学习笔记_Hessian
Hessian
如果读者想快速了解相关配置原理的,可以直接从3.3节开始浏览
1、hessian简介
1.1 hessian是什么
hessian是一个轻量级的remoting onhttp工具,使用简单的方法提供了RMI的功能。相比WebService,hessian更简单、快捷。采用的是二进制的RPC协议,因为采用的是二进制协议,所以它很适合于发送二进制数据。
1.2 hessian的优缺点
优点:
比 Java 原生的对象序列化/反序列化速度更快,,序列化出来以后的数据更小。序列化协议跟应用层协议无关, 可以将 Hessian 序列化以后的数据放在 HTTP Body 里,,也可以放在 DUBBO 里,,或者直接用 Socket 传输。Hessian协议和web service常用的SOAP协议类似,也是将协议报文封装在HTTP封包中,通过HTTP信道进行传输的。因此Hessian协议具有与SOAP协议同样的优点——传输不受防火墙的限制(防火墙通常不限制HTTP信道),不需要配置防火墙。
Hessian类似于Webservice,但是它不使用soap协议,它把协议报文封装到http封包中,通过HTTP信道传输。是一种高效简洁的远程调用框架,它采用的是二进制RPC协议(Binary),具有轻量、传输量小、平台无关的特点,特别适合于目前网络带宽比较小的手机网络应用项目。简单易用,面向接口,通过接口暴露服务,jar包只有200、300k,效率高,复杂对象序列化速度仅次于RMI,简单对象序列化优于RMI,二进制传输多语言支持。为什么序列化后数据更小呢?因为:
它把本地格式的数据编码为二进制数据,仅用一个字符作为结构化标记,HBWSP封装后的数据增量明显小于SOAP封装后的数据增量。并且相对于SOAP,Hessian协议的外部数据表示有3个显著的优势:
- 采用简单的结构化标记。简单的结构化标记减少了编码、解码操作对内存的占用量。编码时,只需写少量的数据,就可以标记结构;解码时,只需读少量的数据就可以确定结构。而且,简单的结构化标记减少了编码后的数据增量。
- 采用定长的字节记录值。用定长的字节记录值,解码时,就可以使用位操作从固定长度的位获得值。这样不仅操作简单,而且可以获得较高的性能。
- 采用引用取代重复遇到的对象。使用引用取代重复遇到的对象可以避免对重复对象的编码,而且也减少了编码后的数据量。
因此使用Hessian协议传输数据量比SOAP协议要小得多。实践证明,传输同样的对象Hessian协议传输的数据量比SOAP协议低一个数量级。因此Hessian协议比SOAP协议更适用于分布式应用系统间大数据量的数据交换
Hessian是通过servlet提供远程服务,完全使用动态代理来实现的,推荐采用面向接口编程,因此,Hessian服务建议通过接口暴露。hessian已经支持Java,Flash/Flex,Python,C++,.NET C#,D,Erlang,PHP,Ruby,Objective C。
缺点
如果service层中返回的对象是复杂对象,使用它就会削弱Hessian的传输量小的优点,而且也会增加Hessian客户端的代码量。既然它是把对象序列化为二进制流的形式在http信道中传输,那么对于安全性高的应用不应该采用hessian(比如网上支付等)。缺乏安全机制,传输没有加密处理, 异常机制不完善,总是报一些错误,错误原因也是千奇百怪,提示信息不足, 事务处理欠缺, 版本问题,spring 2.5.6对照3.1.3版,spring 3对照4.0及以上版本,需要使用spring MVC。
关于hession和其他通讯RPC方式的一些比较
-
和dubbo对比:dubbo支持多种远程调用方式,例如dubbo RPC(二进制序列化 + tcp协议)、http invoker(二进制序列化 + http协议,至少在开源版本没发现对文本序列化的支持)、hessian(二进制序列化 + http协议)、WebServices (文本序列化 + http协议)等等...
-
和RMI,HTTPINvoker等对比
通讯效率测试结果:
RMI > Httpinvoker >= Hessian >> Burlap >> Web service- RMI 是 Java 首选远程调用协议,非常高效稳定,特别是在数据结构复杂,数据量大的情况下,与其他通讯协议的差距尤为明显。但不能跨语言
- HttpInvoker 使用 java 的序列化技术传输对象,与 RMI 在本质上是一致的。从效率上看,两者也相差无几, HttpInvoker 与 RMI 的传输时间基本持平。
- Hessian 在传输少量对象时,比 RMI 还要快速高效,但传输数据结构复杂的对象或大量数据对象时,较 RMI 要慢 20% 左右。但这只是在数据量特别大,数据结构很复杂的情况下才能体现出来,中等或少量数据时, Hessian并不比RMI慢。 Hessian 的好处是精简高效,可以跨语言使用,而且协议规范公开,我们可以针对任意语言开发对其协议的实现。另外, Hessian与WEB服务器结合非常好,借助WEB服务器的成熟功能,在处理大量用户并发访问时会有很大优势,在资源分配,线程排队,异常处理等方面都可以由成熟的WEB服务器保证。而 RMI 本身并不提供多线程的服务器。而且,RMI 需要开防火墙端口, Hessian 不用。
- Burlap 采用 xml 格式传输。仅在传输 1 条数据时速度尚可,通常情况下,它的毫时是 RMI 的 3 倍。
- Web Service 的效率低下是众所周知的,平均来看, Web Service 的通讯毫时是 RMI 的 10 倍。
1.3 关于hessian的7个问题
- 是基于什么协议实现的?
基于Binary-RPC协议实现。 - 怎么发起请求?
需通过Hessian本身提供的API来发起请求。 - 怎么将请求转化为符合协议的格式的?
Hessian通过其自定义的串行化机制将请求信息进行序列化,产生二进制流。 - 使用什么 传输协议传输?
Hessian基于Http协议进行传输。 - 响应端基于什么机制来接收请求?
响应端根据Hessian提供的API来接收请求。 - 怎么将流还原为传输格式的?
Hessian根据其私有的串行化机制来将请求信息进行反序列化,传递给使用者时已是相应的请求信息对了。 - 处理完毕后怎么回应?
处理完毕后直接返回,hessian将结果对象进行序列化,传输至调用端。
2、RPC框架
2.1 RPC简介
RPC是指远程过程调用,也就是说两台服务器A,B,一个应用部署在A服务器上,想要调用B服务器中应用提供的函数/方法,由于不在一个内存空间,不能直接调用,需要通过网络来表达调用的语法和传达调用的数据。
比如,一个方法如下定义:
Employee getEmployeeByName(String fullName)
那么:
- 要解决通讯问题,主要是通过在客户端和服务器之间建立TCP连接,远程过程调用的所有交换的数据都会在这个连接里传输。连接可以是按需连接,调用结束后就断掉,也可以是长连接,多个远程调用共享同一个连接。
- 要解决寻址问题,也就是说,A服务器上的应用要怎么告诉底层的RPC框架,如何连接到B服务器(如主机或IP地址)以及特定的端口,方法的名称。这样才能完成调用。比如基于Web服务协议栈的RPC,就要提供一个endpoint URI,或者从UDDI服务上查找。如果是RMI调用的话,还需要一个RMI Registry来注册服务的地址。
- 当A服务器上的应用发起远程过程调用时,方法的参数需要通过底层的网络协议如TCP传递到B服务器,由于网络协议是基于二进制的,内存中的参数的值要序列化成二进制的形式,也就是序列化(Serizlize)或编组(marshal),通过寻址和传输将序列化的二进制发送给B服务器。
- B服务器收到请求后,需要对参数进行反序列化,恢复为内存中的表达方式,然后找到对应的方法(寻址的一部分)进行本地调用,然后得到返回值。
- 返回值还要发送回服务器A上的应用,也要经过序列化的方式发送,服务器A接到后在反序列化,恢复为内存中的表达方式,交给A服务器上的应用。
2.2 为什么需要RPC
现在的应用程序的功能和模块无法在一台服务器上完成,为了提高效率,采用分布式的方式进行布局已然成为主流。在不同系统间的通讯,甚至是不同组织间的通讯,就需要通过PRC来实现。
RPC的协议有很多,比如最早的CORBA, JAVA RMI, Web Service的RPC风格,hessian, Thrift 甚至Rest API
3、hessian基本使用
项目目录结果如下:
api:客户端和服务端均共同引用的接口api
hessianclient:客户端调用,包括本地直接通过代理对象以及Spring集成方式调用
hessianserver:通过传统servlet方式提供服务
hessianserver-spring:与Spring集成提供服务
创建普通maven项目hessian,删除其中的src目录项。将整个项目作为父项目,然后根据需要创建子项目即可
可以把一些公共的依赖放在父目录下的pom.xml中
<dependencies>
<!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.20</version>
<scope>provided</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/com.caucho/hessian -->
<dependency>
<groupId>com.caucho</groupId>
<artifactId>hessian</artifactId>
<version>4.0.65</version>
</dependency>
</dependencies>
3.1 新建maven项目api
接口IHello
package top.saodisheng;
import top.saodisheng.entity.User;
import java.util.List;
import java.util.Map;
/**
* Description:
*
* @author 扫地生_saodisheng
* @date 2021/06/25
*/
public interface IHello {
public String sayHello(String name);
public String getUserList(List<User> users);
public String getUserMap(Map<String, User> maps);
}
实体类User:
package top.saodisheng.entity;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
/**
* Description:
*
* @author 扫地生_saodisheng
* @date 2021/06/25
*/
@Data
@AllArgsConstructor@NoArgsConstructor
public class User implements Serializable {
private static final long serialVersionUID = 1L;
private String userName;
private String password;
}
3.2 通过传统的servlet实现RPC
服务端
1、新建maven web项目hessianserver
2、导入依赖
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
<!--导入api-->
<dependency>
<groupId>top.saodisheng</groupId>
<artifactId>hessianapi</artifactId>
<version>1.0-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
</dependencies>
3、创建api公共接口对应的实现类IHelloImpl
package top.saodisheng.impl;
import top.saodisheng.IHello;
import top.saodisheng.entity.User;
import java.util.List;
import java.util.Map;
/**
* Description:
*
* @author 扫地生_saodisheng
* @date 2021/06/25
*/
public class IHelloImpl implements IHello {
@Override
public String sayHello(String name) {
return "Hello " + name;
}
@Override
public String getUserList(List<User> users) {
StringBuffer userString = new StringBuffer();
for (User user : users) {
userString.append(user.toString());
}
return userString.toString();
}
@Override
public String getUserMap(Map<String, User> maps) {
StringBuffer userString = new StringBuffer();
for (Map.Entry e : maps.entrySet()) {
userString.append(e.getValue());
}
return userString.toString();
}
}
4、配置Tomcat
5、web.xml中配置hessian Servlet
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<!-- hessian-->
<servlet>
<servlet-name>Hello</servlet-name>
<servlet-class>com.caucho.hessian.server.HessianServlet</servlet-class>
<init-param>
<param-name>home-class</param-name>
<param-value>top.saodisheng.impl.IHelloImpl</param-value>
</init-param>
<init-param>
<param-name>home-api</param-name>
<param-value>top.saodisheng.IHello</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>Hello</servlet-name>
<url-pattern>/Hello</url-pattern>
</servlet-mapping>
</web-app>
客户端
1、新建普通maven项目hessianclient
2、添加依赖
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
<!--导入api-->
<dependency>
<groupId>top.saodisheng</groupId>
<artifactId>hessianapi</artifactId>
<version>1.0-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
</dependencies>
3、编写测试类
package test;
import com.caucho.hessian.client.HessianProxyFactory;
import top.saodisheng.IHello;
import top.saodisheng.entity.User;
import java.net.MalformedURLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* Description:
* 传统的servlet方法调用
* @author 扫地生_saodisheng
* @date 2021/06/25
*/
public class ClientTest {
public static String url = "http://127.0.0.1:8080/Hello";
public static void main(String[] args) {
HessianProxyFactory factory = new HessianProxyFactory();
try {
// 从代理工厂中生成一个实例
IHello iHello = (IHello) factory.create(IHello.class, url);
// 模拟数据
User user1 = new User("saodisheng", "123");
User user2 = new User("扫地生", "321");
List<User> userList = new ArrayList<>();
userList.add(user1);
userList.add(user2);
Map<String, User> userMap = new HashMap<>();
userMap.put("user1", user1);
userMap.put("user2", user2);
// 调用远程方法,看看是否正常工作
System.out.println(iHello.sayHello("saodisheng"));
System.out.println(iHello.getUserList(userList));
System.out.println(iHello.getUserMap(userMap));
} catch (MalformedURLException e) {
e.printStackTrace();
}
}
}
4、启动服务器,测试
3.3 hessian配置说明
hessian是实现webservice的一个框架,
hessian传输是http协议之上应用层协议(hessian自定义二进制rpc协议)。
hessian传输小数量数据速度很快。
使用hessian+spring开发webservice的流程:
服务端:
1. 编写dao,service方法
2. 使用spring容器发布服务,
3. 在web.xml配置hessian的servlet
下面是spring配置文件中发布服务接口的方法
<!-- hessian服务
HessianServiceExporter:将service指定的bean生成hessian服务接口
service:提供hessian接口服务的bean
serviceInterface:Hessian服务的接口
-->
<bean name="/ypxxRemoteService"
class="org.springframework.remoting.caucho.HessianServiceExporter">
<property name="service" ref="ypxxService" />
<property name="serviceInterface">
<value>
cn.xxxx.yycg.hessian.server.YpxxService
</value>
</property>
</bean>
------<!-- hessian和spring整合,配置hessian servlet -->
<servlet>
<servlet-name>Hessian</servlet-name>
<servlet-class>
org.springframework.web.servlet.DispatcherServlet
</servlet-class>
<!-- hessian-service.xml配置hessian服务信息 -->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:hessian/hessian-service.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>Hessian</servlet-name>
<!-- hessian的接口地址=http://ip:port/hessian/hessian-service.xml文件中配置的地址 -->
<url-pattern>/hessian/*</url-pattern>
</servlet-mapping>
客户端:
1.使用spring容器创建service的代理对象, 首先把服务端接口及相关的类拷贝到客户端工程,
注意:包名与服务端包名必须一致
<!-- 配置客户端存根 代理对象 -->
<bean id="ypxxServiceProxy" class="org.springframework.remoting.caucho.HessianProxyFactoryBean">
<!-- 配置代理对象的类型即服务端接口类型UserService -->
<property name="serviceInterface">
<value> cn.xxxx.yycg.hessian.server.YpxxService</value>
</property>
<!-- 配置调用服务端接口地址 -->
<property name="serviceUrl">
<value> http://localhost:8080/yycg_sheng/hessian/ypxxRemoteService
</value>
</property>
</bean>
2.在客户端调用服务的方法中注入代理对象的实例,通过代理对象调用方法.
3.4 通过Spring集成hessian实现RPC、
服务端
1、新建maven web项目hessianserver
2、导入依赖
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
<!--导入api-->
<dependency>
<groupId>top.saodisheng</groupId>
<artifactId>hessianapi</artifactId>
<version>1.0-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
<!-- spring -->
<!-- https://mvnrepository.com/artifact/org.springframework/spring-web -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>5.3.8</version>
</dependency>
<!--spring mvc-->
<!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.3.8</version>
</dependency>
</dependencies>
3、创建api公共接口对应的实现类IHelloImpl
package top.saodisheng.impl;
import top.saodisheng.IHello;
import top.saodisheng.entity.User;
import java.util.List;
import java.util.Map;
/**
* Description:
*
* @author 扫地生_saodisheng
* @date 2021/06/25
*/
public class IHelloImpl implements IHello {
@Override
public String sayHello(String name) {
return "Hello " + name;
}
@Override
public String getUserList(List<User> users) {
StringBuffer userString = new StringBuffer();
for (User user : users) {
userString.append(user.toString());
}
return userString.toString();
}
@Override
public String getUserMap(Map<String, User> maps) {
StringBuffer userString = new StringBuffer();
for (Map.Entry e : maps.entrySet()) {
userString.append(e.getValue());
}
return userString.toString();
}
}
4、配置Tomcat
5、applicationContext.xml中配置hessian服务
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.1.xsd"
default-lazy-init="true">
<!--注入提供服务的bean-->
<bean name="helloService" class="top.saodisheng.impl.IHelloImpl"></bean>
<!--
HessianServiceExport:将service指定的bean生成hessian服务接口
service:提供hessian接口服务的bean
serviceInterface:hessian服务的接口
-->
<bean name="/helloRemoteService" class="org.springframework.remoting.caucho.HessianServiceExporter">
<property name="service" ref="helloService"></property>
<property name="serviceInterface">
<value>top.saodisheng.IHello</value>
</property>
</bean>
</beans>
6、webt.xml中配置整合Spring和hessian
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<!-- hessian和spring整合,配置hessian servlet -->
<servlet>
<servlet-name>hello</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!-- applicationContext.xml配置hessian服务信息 -->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>hello</servlet-name>
<!-- hessian的接口地址 = http://ip:prot/saodishengRemoteService/applicationContext.xml文件中配置的地址-->
<url-pattern>/saodishengRemoteService/*</url-pattern>
</servlet-mapping>
</web-app>
客户端
1、在hessianclient项目中添加依赖,添加后依赖如下:
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
<!--导入api-->
<dependency>
<groupId>top.saodisheng</groupId>
<artifactId>hessianapi</artifactId>
<version>1.0-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.3.8</version>
<scope>compile</scope>
</dependency>
<!-- spring -->
<!-- https://mvnrepository.com/artifact/org.springframework/spring-web -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>5.3.8</version>
</dependency>
<!--spring mvc-->
<!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.3.8</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-beans -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>5.3.8</version>
</dependency>
</dependencies>
2、编写客户端配置文件applicationContext-hessian.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.1.xsd"
default-lazy-init="true">
<!-- 配置客户端存根 代理对象-->
<bean name="helloServiceProxy" class="org.springframework.remoting.caucho.HessianProxyFactoryBean">
<!-- 配置代理对象的类型即服务端对应接口类型-->
<property name="serviceInterface">
<value>top.saodisheng.IHello</value>
</property>
<!-- 配置服务端暴露出来的接口地址-->
<property name="serviceUrl">
<value>http://localhost:8080/saodishengRemoteService/helloRemoteService</value>
</property>
</bean>
</beans>
3、编写测试类
package test;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import top.saodisheng.IHello;
import top.saodisheng.entity.User;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* Description:
* 整合Spring调用远程方法
* @author 扫地生_saodisheng
* @date 2021/06/25
*/
public class Client_springTest {
public static void main(String[] args) {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext-hessian.xml");
// 获取实例
IHello helloService = (IHello)context.getBean("helloServiceProxy");
// 模拟数据
User user1 = new User("saodisheng", "123");
User user2 = new User("spring", "321");
List<User> userList = new ArrayList<>();
userList.add(user1);
userList.add(user2);
Map<String, User> userMap = new HashMap<>();
userMap.put("user1", user1);
userMap.put("user2", user2);
// 调用远程方法,看看是否正常工作
System.out.println(helloService.sayHello("saodisheng"));
System.out.println(helloService.getUserList(userList));
System.out.println(helloService.getUserMap(userMap));
}
}
4、启动服务器,测试
4、探究hessian实现细节
回到文章开始提出的问题,即pc框架需要解决的问题,看看hessian如何解决的。
4.1 通讯问题:
我们先看看客户端在发起远程请求前都经历了什么:
首先,客户端通过代理工厂对象HessianProxyFactory的create方法创建代理对象;
我们跟踪进入create方法里可以看到,该代理对象在执行时的handler是通过HessianProxy代理对象的invoke方法来执行;典型的动态代理;
在invoke方法中:
通过String methodName = method.getName();得到方法名
通过sendRequest方法取得和服务端的连接HessianConnection对象;
跟踪sendRequest方法,我们发现:
发现,hessian是使用http协议进行网络通信;
在is = getInputStream(conn);处等待服务端返回的响应;
4.2 寻址问题
我们跟踪这里:
我们得出结论:hessian使用lookup方法来寻找远程服务;
4.3 序列化与反序列化
我们继续看刚刚跟踪的客户端调用时执行的HessianProxy对象的invoke方法,
进入其中的
conn = sendRequest(mangleName, args);
再进入
out.call(methodName, args);
再进入
writeObject(args[i]);
进入其Hessian2Output实现中
最终看到了hessian如何进行序列化:
serializer.writeObject(object, this);
至此,我们也可以梳理一下hessian客户端动态代理的执行流程:
我们再来看看服务端的执行细节:
通过后台的代码,可见我们所有的工作都围绕在HessianServlet在展开。该Servlet中有两个比较重要的方法:init()、service();
init方法初始化服务和服务对象,主要分为3步:
通过home-class或者service-class创建服务端的实现类实例;
init方法还会创建HessianSkeleton对象,这是Hessian服务端的核心功能部分。
HessianSkeleton继承自AbstractSkeleton,其构造方法,将会从实现类中抽取方法和方法的Method对象,并且存储到_methodMap中。
对于一个Servlet来说其service方法是对外提供服务的方法:
最主要的是调用HessianSkeleton对象的invoke方法。注意,Servlet实例中有两个HessianSkeleton变量,分别是:_objectSkeleton和 _homeSkeleton,
invoke方法:
首先从HessianInput对象中获取到Method信息,获取到真正的service对象。
根据反射机制,调用service对象的invoke方法,获取到返回值。
最后调用HessianOutput对象将结果写回到调用方。