参考自简书

https://www.jianshu.com/p/9136aa36cffb

案例场景为单向通信

A 和 B两个应用服务, B需要调用A的接口完成业务需求

那么A服务角色就是服务端,提供给B服务,B服务角色就是客户端,请求A服务接口

服务端 8081

客户端 8082

新建两个SpringBoot的Web服务

导入Hessian组件包

        <!-- hessian -->
<dependency>
<groupId>com.caucho</groupId>
<artifactId>hessian</artifactId>
<version>4.0.38</version>
</dependency>

服务端提供:

1、业务接口

package cn.cloud9.hessianserver.service;

public interface HelloHessian {
String hello(String message);
}

2、业务实现

package cn.cloud9.hessianserver.service;

import org.springframework.stereotype.Service;

@Service("HelloHessian")
public class HelloHessianImpl implements HelloHessian{ @Override
public String hello(String message) {
return "From Hessian Server, Message: " + message;
}
}

3、Hessian服务转换配置

package cn.cloud9.hessianserver.config;

import cn.cloud9.hessianserver.service.HelloHessian;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.remoting.caucho.HessianServiceExporter; import javax.annotation.Resource; @Configuration
public class HessianServerConfiguration { @Resource
HelloHessian helloHessian; /**
* 1. HessianServiceExporter是由Spring.web框架提供的Hessian工具类,能够将bean转化为Hessian服务
* 2. @Bean(name = "/helloHessian.do")加斜杠方式会被spring暴露服务路径,发布服务。
* @return
*/
@Bean("/helloHessian.do")
public HessianServiceExporter exportHelloHessian() {
HessianServiceExporter exporter = new HessianServiceExporter();
exporter.setService(helloHessian);
exporter.setServiceInterface(HelloHessian.class);
return exporter;
} }

除此以外,服务端无任何配置

客户端提供:

1、和Hessian服务中一样声明的接口

package cn.cloud9.hessianclient.service;

public interface HelloHessian {
String hello(String message);
}

2、代理工厂将接口实现化

package cn.cloud9.hessianclient.util;
import com.caucho.hessian.client.HessianProxyFactory; public class HessianProxyFactoryUtil { /**
* 获取调用端对象
* @param clazz 实体对象泛型
* @param url 客户端url地址
* @param <T>
* @return 业务对象
*/
public static <T> T getHessianClientBean(Class<T> clazz,String url) throws Exception {
// 客户端连接工厂,这里只是做了最简单的实例化,还可以设置超时时间,密码等安全参数
HessianProxyFactory factory = new HessianProxyFactory(); return (T)factory.create(clazz,url);
}
}

3、调用即实现

package cn.cloud9.hessianclient.controller;

import cn.cloud9.hessianclient.service.HelloHessian;
import cn.cloud9.hessianclient.util.HessianProxyFactoryUtil;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController; @RestController
@RequestMapping("/test")
public class TestController { @GetMapping("/hello")
public String hello() {
// 服务器暴露出的地址
String url = "http://localhost:8081/helloHessian.do";
String msg = null;
// 客户端接口,需与服务端对象一样
try {
HelloHessian helloHessian = HessianProxyFactoryUtil.getHessianClientBean(HelloHessian.class,url);
msg = helloHessian.hello("你好"); System.out.println(msg); } catch (Exception e) {
e.printStackTrace();
} return msg;
}
}

两个服务开启后,访问客户端的服务URL

localhost:8082/test/hello

访问成功

复盘一下:

服务端 提供了 接口规范,接口实现,Hessian服务实例

客户端 提供 接口规范, Hessian服务转换, 服务地址 + (接口名?)

如果不是字符串,需要传递复杂的对象类型,则需要进行序列化处理

@Data
@AllArgsConstructor
@NoArgsConstructor
public class User implements Serializable {
private Integer id;
private String name;
private Integer age;
private String email;
}

Hessian服务接口新增一个方法

List<User> getUserList2();

业务实现:

    @Override
public List<User> getUserList2() {
return userMapper.selectList(new QueryWrapper<>());
}

如果服务端的User类没有实现序列化接口,则会报错

PO的User类实现序列化接口后可以正常传输

[{"age":18,"email":"test1@baomidou.com","id":1,"name":"Jone"},{"age":20,"email":"test2@baomidou.com","id":2,"name":"Jack"},{"age":28,"email":"test3@baomidou.com","id":3,"name":"Tom"},{"age":21,"email":"test4@baomidou.com","id":4,"name":"Sandy"},{"age":24,"email":"test5@baomidou.com","id":5,"name":"Billie"}]
[User(id=1, name=Jone, age=18, email=test1@baomidou.com), User(id=2, name=Jack, age=20, email=test2@baomidou.com), User(id=3, name=Tom, age=28, email=test3@baomidou.com), User(id=4, name=Sandy, age=21, email=test4@baomidou.com), User(id=5, name=Billie, age=24, email=test5@baomidou.com)]

关于Hessian序列化的潜在问题:

同名子类序列化报错问题

https://www.cnblogs.com/yfyzy/p/7197679.html

在项目中的应用:

权限系统是一个独立的服务

酒店端系统需要开发一个PC桌面端的应用程序

PC应用程序的登录接口通过 酒店端Web提供

那酒店程序没有权限的功能,需要找到权限系统要这个数据

所以权限系统提供了一个远程访问接口给其它服务调用

这里就采用了Hessian来实现

一、生产者配置

首先这里的权限系统是Portal-Server

关于Hessian提供的服务规范在Portal-New-Client包里面

先来看客户端包的定义:

可以发现,只有PO和接口

接口这里我只展示我需要调用的这个方法

package cn.ymcd.portal_new.service;

import java.util.List;

import cn.ymcd.portal_new.dto.AppDTO;
import cn.ymcd.portal_new.dto.AreaDTO;
import cn.ymcd.portal_new.dto.FuncDTO;
import cn.ymcd.portal_new.dto.OrgDTO;
import cn.ymcd.portal_new.dto.UserDTO; /**
* portal所有功能接口,供rpc远程调用,供2019-7提供的新框架使用
*
* @projectName:portal-new-client
* @author:lianss
* @date:2019年7月22日 下午2:49:58
* @version 1.0
*/
public interface IPortalNewService { /**
* 根据ID获取用户信息(只包含用户基本信息)
* @param id 用户主键ID
* @return
* @author:lianss
* @createTime:2019年1月24日 上午9:23:40
*/
UserDTO findUser(String id);
}

然后Portal-Server作为服务端

实现了这个服务规范,并且将服务实现交给Hessian组件进行了封装

服务的实现:

package cn.ymcd.portal.rpc;

import java.util.ArrayList;
import java.util.List; import cn.ymcd.portal_new.dto.*;
import com.google.common.collect.Lists;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils; import com.alibaba.fastjson.JSON; import cn.ymcd.comm.log.LogFactory;
import cn.ymcd.comm.log.YmcdLogger;
import cn.ymcd.portal.area.search.AreaSearchForm;
import cn.ymcd.portal.area.service.AreaService;
import cn.ymcd.portal.org.search.OrgSearchForm;
import cn.ymcd.portal.org.service.OrgService;
import cn.ymcd.portal.service.IPortalService;
import cn.ymcd.portal.user.search.UserSearchForm;
import cn.ymcd.portal.user.service.UserService;
import cn.ymcd.portal_new.service.IPortalNewService; /**
* portal rpc服务,提供给spring boot+mybatis框架使用
*
* @projectName:portal-server
* @author:lianss
* @date:2019年7月22日 下午4:05:26
* @version 1.0
*/
@Service("portalNewService")
public class PortalNewServiceImpl implements IPortalNewService {
protected YmcdLogger _logger = LogFactory.getLogger(getClass()); @Autowired
private IPortalService portalService;
@Autowired
private UserService userService;
@Autowired
private OrgService orgService;
@Autowired
private AreaService areaService;

@Override
public UserDTO findUser(String id) {
cn.ymcd.portal.dto.UserDTO user = portalService.findUser(id); return copyPorperties(user, UserDTO.class
);
}

}

Hessian配置:

package cn.ymcd.portal.rpc;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.remoting.caucho.HessianServiceExporter; import cn.ymcd.portal.service.IPortalService;
import cn.ymcd.portal_new.service.IPortalNewService; /**
* 通过Hessian把portal service发布出去
*
* @projectName:portal-server
* @author:lianss
* @date:2019年1月24日 下午7:15:10
* @version 1.0
*/
@Configuration
public class HessianServiceConfig {

@Autowired
private IPortalNewService portalNewService;
@Bean(name = "/portal_new/service")
public HessianServiceExporter portalNewService() {
HessianServiceExporter exporter = new PortalHessianServiceExporter();
exporter.setService(portalNewService);
exporter.setServiceInterface(IPortalNewService.class); return
exporter;
}

}

二、消费者配置

回到酒店端服务,酒店端消费这个服务

首先需要客户端组件:

        <!-- hessian -->
<dependency>
<groupId>com.caucho</groupId>
<artifactId>hessian</artifactId>
<version>4.0.38</version>
</dependency>
<!-- provider -->
<dependency>
<groupId>cn.ymcd.portal</groupId>
<artifactId>portal-new-client</artifactId>
<version>1.0.5</version>
</dependency>

然后配置客户端如何调用生产者的服务:

这里生产者和消费者的服务的关系是固定的,没有说双方既是生产者又做消费者

package cn.ymcd.aisw.config;

import cn.ymcd.portal_new.service.IPortalNewService;
import cn.ymcd.wss.util.log.YmcdLogger;
import com.caucho.hessian.client.HessianProxyFactory;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.remoting.caucho.HessianProxyFactoryBean; /**
* 通过Hessian获取tcp service
*
* @version 1.0
* @projectName:wssapi
* @author:wangkun
* @date:2020年6月3日 下午7:02:12
*/
@Configuration
public class HessianTcpClientConfig { private static final YmcdLogger LOGGER = new YmcdLogger(HessianTcpClientConfig.class); @Value("${tcp.server.url}")
private
String tcpServiceUrl; @Value("${tcp.server.timeout:60000}")
private long timeout; @Bean("portalNewService")
public HessianProxyFactoryBean tcpClient() {
HessianProxyFactoryBean factory = new HessianProxyFactoryBean();
if (StringUtils.isNotBlank(tcpServiceUrl)) {
HessianProxyFactory proxyFactory = new HessianProxyFactory();
factory.setProxyFactory(proxyFactory);
factory.setOverloadEnabled(true);
factory.setServiceUrl(tcpServiceUrl + "/portal_new/service");
// 连接超时时间
factory.setConnectTimeout(timeout);
// 读取超时时间
factory.setReadTimeout(timeout);
factory.setServiceInterface(IPortalNewService.class);
} else {
LOGGER.info("wssapi tcp.service.url参数为空或未配置!");
}
return factory;
}
}

这里的代理工厂的获取服务Bean方法和上面的案例不太一样

只有最简陋的getObject方法,拿到对象之后需要自己进行强转处理

package cn.ymcd.aisw.common.controller;

import cn.ymcd.aisw.common.Constant;
import cn.ymcd.aisw.room.service.IMerchantDictService;
import cn.ymcd.comm.security.user.LoginUserContext;
import cn.ymcd.comm.security.user.UserContext;
import cn.ymcd.portal_new.dto.UserDTO;
import cn.ymcd.portal_new.service.IPortalNewService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.remoting.caucho.HessianProxyFactoryBean;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController; import java.util.List;
import java.util.Map; /**
* @projectName: aisw-root
* @author: cloud9
* @date: 2022年03月24日 15:02
* @version: 1.0
*/
@RestController
@RequestMapping("${sys.path}/common")
public class CommonController { @Autowired
IMerchantDictService iMerchantDictService; @Autowired
HessianProxyFactoryBean portalNewService;/**
* /sys/common/loginInterface
* 提供给桌面小程序的登录接口?
* @param
* @return cn.ymcd.portal_new.dto.UserDTO
* @author cloud9
* @createTime 2022/3/28 13:34
*
*/
@GetMapping("/loginInterface")
public UserDTO getCurrentUserInfo() { // HessianProxy[http://localhost:8077/portal/portal_new/service]
IPortalNewService proxyBean = (IPortalNewService)portalNewService.getObject();
// UserDTO user = proxyBean.findUser(LoginUserContext.getUser().getId()); UserDTO user = proxyBean.findUser(Constant.TEST_SYS_USER_ID); return user;
}
}

服务日志打印:

权限服务和酒店端服务都是本地运行的

2022-03-28 13:39:05.737 [http-nio-8083-exec-1] INFO  org.springframework.web.servlet.DispatcherServlet -
Completed initialization in 21 ms
HessianProxy[http://localhost:8077/portal/portal_new/service]
null

【Hessian】轻量级分布式通信组件的更多相关文章

  1. ZeroMQ——一个轻量级的消息通信组件

    ZeroMQ是一个轻量级的消息通信组件,尽管名字中包含了"MQ",严格上来讲ZeroMQ并不是"消息队列/消息中间件".ZeroMQ是一个传输层API库, 更关 ...

  2. ZeroMQ——一个轻量级的消息通信组件 C#

    ZeroMQ——一个轻量级的消息通信组件 ZeroMQ是一个轻量级的消息通信组件,尽管名字中包含了"MQ",严格上来讲ZeroMQ并不是"消息队列/消息中间件" ...

  3. 轻量级分布式延时任务处理组件easyTask-L-入门篇

    今天给大家介绍一款新武器.我自研的一个java组件easyTask-L.这个是做啥的呢?我之前研发了一款单机版本的easyTask,这次是要介绍另外一款easyTask-L.区别就是后者支持分布式环境 ...

  4. 轻量级分布式 RPC 框架

    @import url(/css/cuteeditor.css); 源码地址:http://git.oschina.net/huangyong/rpc RPC,即 Remote Procedure C ...

  5. 【转】轻量级分布式 RPC 框架

    第一步:编写服务接口 第二步:编写服务接口的实现类 第三步:配置服务端 第四步:启动服务器并发布服务 第五步:实现服务注册 第六步:实现 RPC 服务器 第七步:配置客户端 第八步:实现服务发现 第九 ...

  6. 轻量级分布式 RPC 框架(转)

    RPC,即 Remote Procedure Call(远程过程调用),说得通俗一点就是:调用远程计算机上的服务,就像调用本地服务一样. RPC 可基于 HTTP 或 TCP 协议,Web Servi ...

  7. 一个轻量级分布式RPC框架--NettyRpc

    1.背景 最近在搜索Netty和Zookeeper方面的文章时,看到了这篇文章<轻量级分布式 RPC 框架>,作者用Zookeeper.Netty和Spring写了一个轻量级的分布式RPC ...

  8. 轻量级分布式RPC框架

    随笔- 139  文章- 0  评论- 387  一个轻量级分布式RPC框架--NettyRpc   1.背景 最近在搜索Netty和Zookeeper方面的文章时,看到了这篇文章<轻量级分布式 ...

  9. 基于.NET框架的消息通信组件ZMQ资料汇编-总目录

    ZMQ是一个比较轻量级的消息通信组件,引用官方的说法: “ZMQ (以下 ZeroMQ 简称 ZMQ)是一个简单好用的传输层,像框架一样的一个 socket library,他使得 Socket 编程 ...

  10. 一个轻量级分布式 RPC 框架 — NettyRpc

    原文出处: 阿凡卢 1.背景 最近在搜索Netty和Zookeeper方面的文章时,看到了这篇文章<轻量级分布式 RPC 框架>,作者用Zookeeper.Netty和Spring写了一个 ...

随机推荐

  1. Qt下载、安装及环境搭建

    1  下载 刚开始去的官网下载,需要注册账号,而且还比较麻烦,后来找到了一个安装包的链接,直接下载就好了:http://mirrors.ustc.edu.cn/qtproject/archive/qt ...

  2. pands基础--数据结构:Series

    从本文开始介绍pandas的相关知识. pandas含有是数据分析工作变得更快更简单的高级数据结构和操作工具,是基于numpy构建的. 本章节的代码引入pandas约定为:import pandas ...

  3. webpack代码分割

    在做一些单页应用中,若不做任何处理,所有项目文件会打包为一个文件,这个文件非常的大,造成网页在首次进入时比较缓慢.做了代码分割后,会将代码分离到不同的chunk中,然后进行按需加载这些文件,能够提高页 ...

  4. RT-Thread Studio使用教程

    介绍 RT-Thread Studio是官方出品的一款专门针对RT-Thread嵌入式开发.部署.调试.测试的集成开发环境,它基于Eclipse开源项目开发,极大的提高了嵌入式开发者的开发效率,目前最 ...

  5. 企业级私有仓库Harbor

    仓库的概念也就是用于存储,docker仓库用于存储镜像. 镜像构建完成后,很容易可以在宿主机上运行,但是如果要在其他服务器上运行,则需要考虑镜像的分发,存储的问题. 共有/私有/仓库 Docker R ...

  6. 贝壳找房: 为 AI 平台打造混合多云的存储加速底座

    贝壳机器学习平台的计算资源,尤其是 GPU,主要依赖公有云服务,并分布在不同的地理区域.为了让存储可以灵活地跟随计算资源,存储系统需具备高度的灵活性,支持跨区域的数据访问和迁移,同时确保计算任务的连续 ...

  7. 地铁查询app 结对作业三

    经过今天一下午的奋斗 安卓app 只剩下最难的部分了 最短路径问题 我们考虑用迪杰斯特拉算法 不过 没有做出来 还要继续去学习一下这个代码 并寻求网上代码的帮助

  8. 新浪微博动态 RSA 分析图文+登录

    Tips:当你看到这个提示的时候,说明当前的文章是由原emlog博客系统搬迁至此的,文章发布时间已过于久远,编排和内容不一定完整,还请谅解` 新浪微博动态 RSA 分析图文+登录 日期:2016-10 ...

  9. maven项目创建默认目录结构

    maven项目创建默认目录结构命令 项目文件夹未创建情况下 mvn \ archetype:generate \ -DgroupId=com.lits.parent \ -DartifactId=my ...

  10. CentOS7系统搭建web环境 php&nginx&pgsql

    环境:VMware.CentOS-7-x86_64-DVD-2009.iso.nginx-1.26.1.php-7.2.0.postgresql-12 php最好安装对应php项目所需版本,否则会出现 ...