1 简介

  Hessian 是 Caucho 公司开发的一种基于二进制 RPC 协议(Remote Procedure Call protocol)的轻量级远程调用框架,其使用简单的方法提供了 RMI 的功能。 相比 WebService,Hessian 更简单、快捷,它主要包括 Hessian 远程调用协议、Hessian 序列化协议和客户端服务端代理。特别提示,Hessian 远程调用框架是构建在 HTTP 协议之上的。

2 调用过程

其中,步骤 3、4、5、6 为核心过程,在此进行更深层次的解析,

步骤 3:将远程方法调用转换为 Hessian 调用,具体为,客户端首先要先和服务器端建立 Socket 连接,然后发送 HTTP 请求,Hessian 远程调用将经过 Hessian 序列化的参数等二进制数据作为 HTTP 请求的数据部分被提交到服务端,并且目前只支持 Post 提交方法。

步骤 4:将 Hessian 调用转换为本地方法调用,步骤 3 里请求的 url 是暴露服务时映射好的,也即指定的服务端代理对象会解析客户端服务代理对象进行的 Hessian 远程调用,然后反序列化参数,找到被代理的服务类(暴露服务时指定的服务类),通过反射调用服务类中的相应服务方法。

步骤 5:返回远程调用返回值给服务调用者,步骤 4 里调用服务类的方法会返回具体值,经过 Hessian 序列化后作为 Hessian 调用的返回值,被放在 HTTP 响应的 body 部分被返回给客户端。

步骤 6:客户端代理对象解析 body 部分 Hessian 调用返回 reply,解析出远程调用返回值再反序列化,最终得到结果。

3 注意事项

在进行基于 Hessian 协议的项目开发时,构建的服务端和客户端应该具备如下内容,

服务端:

  • 包含 Hessian 的 jar 包;
  • 设计一个接口,用来给客户端调用;
  • 实现该接口的功能;
  • 配置web.xml,配好相应的 Servlet;
  • 对于复杂对象可以使用 Map 的方法传递;
  • 由于使用二进制 RPC 协议传输数据,对象必须进行序列化,实现 Serializable 接口。

客户端:

  • 包含 Hessian 的 jar 包;
  • 具有和服务器端结构一样的接口;
  • 利用 HessianProxyFactory 调用远程接口。

Hessian 的 jar 包可以通过下面提供的两个地址下载:

  • 方法1 -> hessian-4.0.37(最新版本的jar包)
  • 方法2 -> hessian官方网站

4 调用示例

4.1 示例一

新建一个 Web Project 项目,将 Hessian 的 jar 包导入到External Libraries中:

/**
* 创建接口
*/package com.hit;public interface BasicAPI {public void setGreeting(String greeting);public String hello();public User getUser();
}
/**
* 实现接口
*/package com.hit;public class BasicService implements BasicAPI {private String _greeting = "Hello, hessian";public void setGreeting(String greeting) {_greeting = greeting;System.out.println("Set greeting success:" + _greeting);}public String hello(){return _greeting;}public User getUser() {return new User("charies", "xiaomima");}
}
/**
* 创建一个实现 Serializable 接口的 POJO 类(简单的 Java 类),也可以说是 Bean
*/package com.hit;import java.io.Serializable;public class User implements Serializable {String userName = "charies";String password = "xiaomima";public User(String user, String pwd) {this.userName = user;this.password = pwd;}public String getUserName() {return userName;}public String getPassword() {return password;}
}
<!-- 配置 web.xml --><?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_3_1.xsd"version="3.1"><display-name>Hessian</display-name><servlet><servlet-name>helloHssian</servlet-name><servlet-class>com.caucho.hessian.server.HessianServlet</servlet-class><init-param><param-name>service-class</param-name><param-value>com.hit.BasicService</param-value></init-param></servlet><servlet-mapping><servlet-name>helloHssian</servlet-name><url-pattern>/helloHssian</url-pattern></servlet-mapping></web-app>

接下来,再创建一个 Java Project,导入 Hessian 的 jar 包,并创建与服务器端一样的接口及基础类:

package com.hit;public interface BasicAPI{
public void setGreeting(String greeting);
public String hello();public User getUser();
}
package com.hit;import java.io.Serializable;public class User implements Serializable{String userName ="charies";String password ="xiaomima";public User(String user, String pwd) {this.userName = user;this.password = pwd;}public String getUserName() {return userName;}public String getPassword() {return password;}
}
package com.hit;import com.caucho.hessian.client.HessianProxyFactory;public class BasicClient {public static void main(String[] args) throws Exception {String url ="http://localhost:8080/Hessian/helloHessian";HessianProxyFactory factory = new HessianProxyFactory();BasicAPI basic = (BasicAPI) factory.create(BasicAPI.class, url);System.out.println("Hello:" + basic.hello());System.out.println("Hello:" + basic.getUser().getUserName());System.out.println("Hello:" + basic.getUser().getPassword());basic.setGreeting("HelloGreeting");System.out.println("Hello:" + basic.hello());}
}

4.2 示例二

创建服务端:

/**
* 创建接口
*/package com.hit.hessian.service;public interface Basic {public String sayHello();
}
/**
* 实现接口
*/package com.hit.hessian.service;public class BasicService implements Basic {private String message = "We are champion!";@Overridepublic String sayHello() {return message;}
}
/**
* 实现接口并继承 HessianServlet
*/
package com.hit2.hessian.service;
import com.caucho.hessian.server.HessianServlet;
public class BasicServiceAlso extends HessianServlet implements Basic{private String message = "you you, qie ke nao!";@Overridepublic String sayHello() {return message;}
}
<!-- 配置 web.xml --><?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_3_1.xsd"version="3.1"><display-name>HessianWeb</display-name><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>com.hit.hessian.service.BasicService</param-value>     </init-param>     <init-param>     <param-name>home-api</param-name><param-value>com.hit.hessian.service.Basic</param-value>     </init-param>     </servlet><servlet-mapping>     <servlet-name>hello</servlet-name>     <url-pattern>/helloHessian</url-pattern>     </servlet-mapping><servlet>     <servlet-name>helloAlso</servlet-name>     <servlet-class>com.hit.hessian.service.BasicServiceAlso</servlet-class>         </servlet><servlet-mapping>     <servlet-name>helloAlso</servlet-name><url-pattern>/helloHessianAlso</url-pattern>     </servlet-mapping></web-app>

在服务端端,我们定义了两个 Service,分别为 BasicService 和 BasicServiceAlso,不同之处在于是否继承 HessianServlet,BasicService 是一个 POJO(简单的 Java 类),而 BasicServiceAlso 则是一个 Servlet. 在web.xml里,BasicService 是通过home-classhome-api两个参数传递给 HessianServlet,然后再将 HessianServlet 配置到web.xml的 Servlet 里来实现服务配置到容器的。而 BasicServiceAlso ,则是直接将自己(它自己就是个 Servlet)配置到web.xml的 Servlet 来实现配置到容器中的。如果我们在一个应用中要实现多个 Hessian 服务,应该采用这种方式。

创建客户端:

/**
* 创建与服务器端相同的接口
*/package com.hit.hessian.service;public interface Basic {public String sayHello();
}
/*
* 创建测试客户端
*/package com.hit.hessian.client;import java.net.MalformedURLException;
import com.caucho.hessian.client.HessianProxyFactory;
import com.hit.hessian.service.Basic;public class HessianClient {public static void main(String[] args) throws MalformedURLException {//String url = "http://localhost:8080/HessianWeb/helloHessian";String url = "http://localhost:8080/HessianWeb/helloHessianAlso";HessianProxyFactory factory = new HessianProxyFactory();Basic basic = (Basic)factory.create(Basic.class, url);System.out.println(basic.sayHello());}
}

客户端要定义一个同服务器端一模一样的接口,然后通过 HessianProxyFactory 获得代理,并调用远程服务的方法。注意:这里笔者故意将客户端与服务器端的 Basic 接口的包定义成不同的路径(一个是 com.hit.hessian.service,一个是 com.hit2.hessian.service),经过验证这样是可以的,但是推荐最好两者一模一样。

4.3 常见的异常及错误的解决方案

在运行以上的代码时,一不小心就会报错,常见的异常及错误的解决方法有:

(1)在启动 tomcat 的时候,出现如下问题java.lang.ClassNotFoundException: org.springframework.web.servlet.DispatcherServlet,而在工程中是可以找到相应的 jar 文件,怎么办?

  解决方法:可能是在工程的WEB-INF/lib下面没有加载相应的 jar 文件 。

(2)控制台显示org.springframework.remoting.RemoteAccessException: Cannot access Hessian service at XXX这个异常。

  解决方法:出现这个异常一般是因为服务端操作出现异常引起的,需要重新检查代码。

(3)编译时错误无法访问 javax.servlet.http.HttpServlet ; 未找到 javax.servlet.http.HttpServlet 的类文件。

  解决方法:可能是环境变量没有配置,或者就是根本没有包含该类的jar包,可以参考 「出现 javax.servlet.http.HttpServlet 错误的原因及解决方法」进行解决。

(4)在 WEB-INF 目录下加载完 Hessian 的 jar 包后,代码仍然报错,怎么办?

  解决方法:出现这个情况的时候,我们可以尝试着把 Hessian 的 jar 包再加载到External Libraries里面。

(5)在通过 Hessian 协议进行远程服务调用的过程中,代码总是报错,异常信息提示为HessianConnectionException,如何解决?

  解决方法:出现这种异常的原因有可能是接口的实现类没有进行注入,即通过@component("接口名称,第一个字母小写")注解进行注入,也有可能是代码没有提交到服务器,从而导致代码没有生效。


参考资料:

[1] Hessian - 百度百科
[2] Hessian 轻量级远程调用方案
[3] Hessian 远程接口调用原理
[4] Hessian 轻量级二进制远程调用框架
[5] Hessian 学习
[6] Hessian 简单实用

基于 Hessian 轻量级远程调用的原理及示例相关推荐

  1. react调用api等待返回结果_程序员:RPC远程调用原理浅析

    RPC 基本概念 RPC(Remote Procedure Call)远程过程调用,简单的理解是一个节点请求另一个节点提供的服务 本地过程调用:如果需要将本地student对象的age+1,可以实现一 ...

  2. Rpc远程调用框架的设计与实现(1)

    Rpc远程调用框架的设计与实现 1   Rpc远程调用框架设计概述 1.1  研究背景 1.1.1传统的Web开发方式 在传统的Web应用程序中,一般都是采取请求→刷新→显示的模式.即每当用户通过单击 ...

  3. 《Spring技术内幕》学习笔记17——Spring HTTP调用器实现远程调用

    1.Spring中,HTTPInvoker(HTTP调用器)是通过基于HTTP协议的分布式远程调用解决方案,和java RMI一样,HTTP调用器也需要使用java的对象序列化机制完成客户端和服务器端 ...

  4. SpringCloud 微服务与远程调用测试

    微服务相关简述 微服务架构中的重要角色 服务调用者:可以暂时认为是与用户交互的角色(因为存在微服务之间的调用),可以根据该用户的类型将其赋予不同的服务调用权限,通过一次http请求访问调用对应的微服务 ...

  5. 分布式通信:远程调用

    分布式通信:远程调用 前言 什么是远程调用? 远程调用的原理及应用 RPC 的原理及应用 RMI 的原理及应用 RPC 与 RMI 对比分析 知识扩展:远程过程调用存在同步和异步吗? 总结 前言 分布 ...

  6. WebService 远程调用方法汇总

    WebService 远程调用方法汇总 一.Web Service 二.REST 三.RPC 一.Web Service webservice 即web服务,它是一种跨编程语言和跨操作系统平台的远程调 ...

  7. 戴尔显示rpc服务器,RakNet4远程调用(RPC)--局域网对战基础

    RakNet是一款很优秀的可移植的网络引擎.以高效率著称. 在一般的局域网游戏中(比如CS.魔兽争霸),需要玩家建立一个主机, 然后在局域网内其他玩家发现这个主机,加入主机后玩家会在一个房间里.这时候 ...

  8. Spring HttpInvoker 远程调用

    Spring HttpInvoker 是 spring 框架中的一个远程调用模型,执行基于 HTTP 的远程调用,并使用 java 的序列化机制在网络间传递对象,客户端可以很轻松的像调用本地对象一样调 ...

  9. 远程调用——hessian使用入门

    Hessian是一个轻量级的remoting onhttp工具,使用简单的方法提供了RMI的功能. 相比WebService,Hessian更简单.快捷.采用的是二进制RPC协议,因为采用的是二进制协 ...

最新文章

  1. FCS省选模拟赛 Day5
  2. 整理oracle 树形查询
  3. 高考来了_大数据能做些什么?
  4. C# Math.Round中国式的四舍五入法
  5. 《大话数据结构》第1章 数据结构绪论 1.2 你数据结构怎么学的?
  6. Android应用程序运行方式以及优先级
  7. ASP.NET跨页面传值技巧总结
  8. ubantu中rpm转换成deb(软件包格式)
  9. go interface类型转换_Go语言的九大核心特性主要有哪些?
  10. 1 个 AI 模型 = 5 辆汽车终身碳排量,AI 为何如此耗能?
  11. maven的pom文件出现Multiple annotations found at this line...,已解决
  12. 介绍 JavaScript 中的闭包、局部变量(局部作用域)和私有变量等内容
  13. 泰安的雾霾确实有点大
  14. 计算机软件资产代码,事业单位六大类固定资产代码.xls
  15. Oracle字符集的简单图解,中文乱码解决
  16. 电脑主板RS232串口硬件设计
  17. python统计汉字个数是_使用 Python 统计中文字符的数量
  18. 摄影后期软件darktable介绍、汉化、使用说明(Lightroom免费替代品)
  19. KILL THE PHARAOH ACUPUNCTURE X 法老联乘系列发布
  20. 博客管理系统之软件测试计划

热门文章

  1. 漆学军:MT4平台量化交易故事
  2. Fedora 17/18 x86_64 安装金山wps office
  3. 字节与位的关系,百兆宽带的百兆是什么意思
  4. 为什么总有人纠结pmp的含金量问题?
  5. 【4大运营商光猫默认初始超级密码】
  6. 巨量,快手,哔哩哔哩平台激活注册上报广告对接
  7. Unicode与中文字符转换
  8. Sa-Token(Java鉴权系统)
  9. 「精品」手绘游戏原画绘画学习的技巧
  10. 亚马逊无货源会成为跨境电商的蓝海吗