(四)远程服务:Hessian 服务实现远程调用 淡淡的烟草味﹌ 2022-05-26 02:50 359阅读 0赞 ### 文章目录 ### * * * * * 前言 * 相比 RMI 而言,Hessian 是跨语言的 * Hessian 基于二进制消息通信 * 序列化的问题 * Spring 4 结合 Hessian 4 * * 服务端的特殊配置 * 客户端的调用 * 关于 Hessian 远程服务的测试 * 一个邪门的问题:客户端可以独立写api接口调用服务吗? ##### 前言 ##### > 在很久之前, 我们一起领略了 RMI 提供远程服务的过程 > https://blog.csdn.net/bestcxx/article/details/79488165 > 本篇我们继续深入下去,了解 Hessian 提供远程服务的过程 ##### 相比 RMI 而言,Hessian 是跨语言的 ##### > RMI 是 Java 语言自己提供的远程调用过程解决方法,它要求服务的提供者和调用者都必须是 Java 语言,而由于 Hessian 对外而言类似于一个 http 服务,所以可以跨语言访问。延伸来说,由于 RMI 需要注册端口和一个随机分配的数据通信端口,导致其会遇到防火墙问题,而 Hessian 借助于 http 服务,可以避免这个问题。 ##### Hessian 基于二进制消息通信 ##### > 和 RMI 一样,Hessian 也是通过二进制消息进行通信的。 ##### 序列化的问题 ##### > Hessian 的序列化机制不同于 Java 的序列化机制,Hessian 的序列化机制相对而言更加快捷,但是可靠性不如java,因为 Hessian 的序列化机制是私有的,所以造成其序列化信息并没有携带全部的信息,这导致在处理复杂对象的时候有时会出现问题。 ##### Spring 4 结合 Hessian 4 ##### > Maven 依赖引入 Hessian 包-服务端和客户端 <dependency> <groupId>com.caucho</groupId> <artifactId>hessian</artifactId> <version>4.0.38</version> </dependency> ###### 服务端的特殊配置 ###### * 类似于 RMI 服务的发布,Hessian 服务的发布也需要先将本地的服务声明为 Hessian 服务 /** * 注册为远程服务 * @return */ @Bean public HessianServiceExporter hessianExportedApiService(){ HessianServiceExporter exporter=new HessianServiceExporter(); exporter.setService(getApiService()); exporter.setServiceInterface(ApiService.class); return exporter; } /** * 注册为Spring Bean * @return */ @Bean public ApiService getApiService(){ return new ApiServiceImpl(); } * 除此之外,还需要设置一个 url 映射,当 web 访问请求符合映射时,将会转由 Hessian 服务来进行处理 /** * 设置URL映射 */ @Bean public HandlerMapping hessianMapping(){ SimpleUrlHandlerMapping shm=new SimpleUrlHandlerMapping(); Properties properties=new Properties(); properties.put("/api.service", "hessianExportedApiService"); shm.setMappings(properties); return shm; } * 最后服务端是一个web工程,所以附带web.xml 的内容 <servlet-mapping> <servlet-name>springservlet</servlet-name> <url-pattern>/</url-pattern> <!-- <url-pattern>*.service</url-pattern> --> </servlet-mapping> ###### 客户端的调用 ###### 客户端的调用过程相对服务端简单了许多 /** * 为远程服务设置代理 * @return */ @Bean public HessianProxyFactoryBean apiService(){ HessianProxyFactoryBean proxy=new HessianProxyFactoryBean(); proxy.setServiceUrl("http://localhost:8086/hessian-provider/api.service"); proxy.setServiceInterface(ApiService.class); return proxy; } * github 完整例子 > https://github.com/Bestcxy/RPC/tree/master/hessian > hessian-api 定义接口 > hessian-provider 提供服务 > hessian-consumer 调用Hessian 服务 * 调用结果 > 启动两个web 项目,访问 http://localhost:8085/hessian-consumer/ {"result":"success","name":"服务端:用户输入了姓名=jecket","model":{"userName":"jecket","age":20}} ##### 关于 Hessian 远程服务的测试 ##### > 当 Hessian 服务启动之后,我们可以通过 Spring 的测试体系对接口进行测试(可以参考 [Junit 使用集合][Junit]),也可以使用 HessianProxyFactory 直接对远程服务进行测试,而且后者会更加简化。这个理由给出 HessianProxyFactory 测试远程接口的方法 package com.bestcxx.stu.rpc.hessian.consumer; import java.net.MalformedURLException; import org.junit.Test; import com.bestcxx.stu.rpc.hessian.api.service.ApiService; import com.caucho.hessian.client.HessianProxyFactory; /** * 使用 HessianProxyFactory 直接测试远程接口的调用 * @author Jecket * */ public class ApiServiceTest { @Test public void testGetName(){ HessianProxyFactory hessianProxyFactory=new HessianProxyFactory(); ApiService apiService; try { apiService=(ApiService) hessianProxyFactory.create(ApiService.class, "http://localhost:8086/hessian-provider/api.service"); System.out.println(apiService.getName("Jecket")); } catch (MalformedURLException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } #### 一个邪门的问题:客户端可以独立写api接口调用服务吗? #### > 标题还不太完整,我再具体阐述一下。 > 本文的例子中,服务端和客户端都依赖 hessian-api项目,该项目定义了接口和抽象方法,实体等信息。 > hessian-provider 提供接口的实现,并发布为 hessian服务,hessian-consumer 通过 hessian-api 中提供的接口和实体来获取 hessian 服务,问,加入hessian-conusmer不依赖 hessian-api,而是在自己的项目中写一套其原本依赖的 接口和实体等,可不可行? > 经过实验发现,是可以的,并且这种情况 Model 的序列号不同也不会有影响。 > 这样做的坏处很明显,就是客户端和服务端的api分离了,加入服务端变更,客户端不知道,但是可以作为一种知识扩充——Java 用包路径+类名+类加载器来唯一限定一个类。 [Junit]: https://blog.csdn.net/bestcxx/article/details/51548997
还没有评论,来说两句吧...