Hession实现远程通讯(基于Binary-RPC协议)
一、开发工具
1.jdk1.6 64位
百度网盘地址:https://pan.baidu.com/s/1Zwqfmi20X4ANNswZzPMzXQ 提取码:k50r
2.apache-maven-3.2.5
百度网盘地址:https://pan.baidu.com/s/1b9ZEnVclXhllmiCoVc3vyQ 提取码:x8jx
3.Eclipse IDE 4.11.0
百度网盘地址:https://pan.baidu.com/s/14_aDA2-xJpQBpDDtDZ_Sag 提取码:5abt
4.apache-tomcat-7.0.68
百度网盘地址:https://pan.baidu.com/s/1SFxj-l8rHpV4e091cT4vGw 提取码:w83x
二、远程通讯协议的基本原理
网络通信需要做的就是将流从一台计算机传输到另外一台计算机,基于传输协议和网络 IO 来实现,其中传输协议比较出名的有 http 、 tcp 、 udp 等等, http 、 tcp 、 udp 都是在基于 Socket 概念上为某类应用场景而扩展出的传输协议,网络 IO ,主要有 bio 、 nio 、 aio 三种方式,所有的分布式应用通讯都基于这个原理而实现,只是为了应用的易用,各种语言通常都会提供一些更为贴近应用易用的应用层协议。
三、应用级协议Binary-RPC
Binary-RPC(Remote Procedure Call Protocol,远程过程调用协议)是一种和RMI(Remote Method Invocation,远程方法调用)类似的远程调用的协议,它和RMI 的不同之处在于它以标准的二进制格式来定义请求的信息 ( 请求的对象、方法、参数等 ) ,这样的好处是什么呢,就是在跨语言通讯的时候也可以使用。
Binary -RPC 协议的一次远程通信过程:
1 、客户端发起请求,按照 Binary -RPC 协议将请求信息进行填充;
2 、填充完毕后将二进制格式文件转化为流,通过传输协议进行传输;
3 、接收到在接收到流后转换为二进制格式文件,按照 Binary -RPC 协议获取请求的信息并进行处理;
4 、处理完毕后将结果按照 Binary -RPC 协议写入二进制格式文件中并返回。
四、Hessian介绍
Hessian是一个轻量级的remoting on http工具,采用的是Binary RPC协议,所以它很适合于发送二进制数据,同时又具有防火墙穿透能力。
它基于HTTP协议传输,使用Hessian二进制序列化,对于数据包比较大的情况比较友好。但是它的参数和返回值都需要实现Serializable接口。
五、示例
1、创建服务端WebServer(Dynamic Web project)转成maven
1)服务注解
/**
* @Title: Service.java
* @Package com.kamfu.annotation
* @Description: TODO(用一句话描述该文件做什么)
* @author: liandy
* @date: 2019年7月26日 下午11:20:28
* @version V1.0
*/
package com.kamfu.annotation; import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target; /**
* @ClassName: Service
* @Description:服务注解类
* @author: liandy
* @date: 2019年7月26日 下午11:20:28
*
*/
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface Service {
String name() default ""; }
Service
2)Class辅助类
/**
* @Title: ClassUtil.java
* @Package kamfu.util
* @Description: TODO(用一句话描述该文件做什么)
* @author: liandy
* @date: 2019年7月26日 下午10:39:29
* @version V1.0
*/
package com.kamfu.util; import java.io.File;
import java.io.IOException;
import java.lang.annotation.Annotation;
import java.net.URL;
import java.util.ArrayList;
import java.util.List; import com.kamfu.annotation.Service; /**
* @ClassName: ClassUtil
* @Description:Class工具类
* @author: liandy
* @date: 2019年7月27日 上午1:32:22
*
*/
public class ClassUtil {
/**
* @Title: getAnnotationClassList
* @Description:获取指定注解的类
* @param: @param an
* @param: @param packageName
* @param: @return
* @param: @throws IOException
* @param: @throws ClassNotFoundException
* @return: List<Class<?>>
* @throws
*/
public static List<Class<?>> getAnnotationClassList(String packageName,Class annotationClass) throws IOException, ClassNotFoundException
{
List<Class<?>> result=new ArrayList<Class<?>>();
List<Class<?>> classes=scanPackage(packageName);
for(Class<?> item :classes)
{
@SuppressWarnings("unchecked")
Object ann=item.getAnnotation(annotationClass);
if(ann!=null)
{
result.add(item);
}
}
return result;
} /**
* 获取同一路径下所有子类或接口实现类
*
* @param intf
* @return
* @throws IOException
* @throws ClassNotFoundException
*/
public static List<Class<?>> getAllAssignedClass(Class<?> cls) throws IOException, ClassNotFoundException {
List<Class<?>> classes = new ArrayList<Class<?>>();
for (Class<?> c : getClasses(cls)) {
if (cls.isAssignableFrom(c) && !cls.equals(c)) {
classes.add(c);
}
}
return classes;
}
public static List<Class<?>> getAllAssignedClass(Class<?> cls,String packageName) throws IOException, ClassNotFoundException {
List<Class<?>> classes = new ArrayList<Class<?>>();
for (Class<?> c : scanPackage(packageName)) {
if (cls.isAssignableFrom(c) && !cls.equals(c)) {
classes.add(c);
}
}
return classes;
} public static List<Class<?>> scanPackage(String packageName) throws IOException, ClassNotFoundException {
String path = packageName.replace('.', '/');
ClassLoader classloader = Thread.currentThread().getContextClassLoader();
URL url = classloader.getResource(path);
return getClasses(new File(url.getFile()), packageName);
} /**
* 取得当前类路径下的所有类
*
* @param cls
* @return
* @throws IOException
* @throws ClassNotFoundException
*/
public static List<Class<?>> getClasses(Class<?> cls) throws IOException, ClassNotFoundException {
String pk = cls.getPackage().getName();
String path = pk.replace('.', '/');
ClassLoader classloader = Thread.currentThread().getContextClassLoader();
URL url = classloader.getResource(path);
return getClasses(new File(url.getFile()), pk);
} /**
* 迭代查找类
*
* @param dir
* @param pk
* @return
* @throws ClassNotFoundException
*/
private static List<Class<?>> getClasses(File dir, String pk) throws ClassNotFoundException {
List<Class<?>> classes = new ArrayList<Class<?>>();
if (!dir.exists()) {
return classes;
}
for (File f : dir.listFiles()) {
if (f.isDirectory()) {
classes.addAll(getClasses(f, pk + "." + f.getName()));
}
String name = f.getName();
if (name.endsWith(".class")) {
classes.add(Class.forName(pk + "." + name.substring(0, name.length() - 6)));
}
}
return classes;
}
}
ClassUtil
3)服务接口
package com.kamfu.service;
/**
* @Title: IBaseService.java
* @Package
* @Description: TODO(用一句话描述该文件做什么)
* @author: liandy
* @date: 2019年7月26日 下午8:35:09
* @version V1.0
*/ /**
* @ClassName: IBaseService
* @Description:TODO(这里用一句话描述这个类的作用)
* @author: liandy
* @date: 2019年7月26日 下午8:35:09
*
*/
public interface IBaseService {
String test();
}
IBaseService
4)服务实现类
/**
* @Title: BaseService.java
* @Package com.kamfu.service
* @Description: TODO(用一句话描述该文件做什么)
* @author: liandy
* @date: 2019年7月26日 下午8:36:11
* @version V1.0
*/
package com.kamfu.service; import com.kamfu.annotation.Service; /**
* @ClassName: BaseService
* @Description:TODO(这里用一句话描述这个类的作用)
* @author: liandy
* @date: 2019年7月26日 下午8:36:11
*
*/
@Service
public class BaseService implements IBaseService{ /**
* <p>Title: test</p>
* <p>Description: </p>
* @return
* @see com.kamfu.service.IBaseService#test()
*/
@Override
public String test() {
// TODO Auto-generated method stub
return "{\"a\":\"1\",\"b\":\"2\"}";
} }
BaseService
5)自定义HessianServlet(可选)
/**
* @Title: MyHessianServlet.java
* @Package com.kamfu.service
* @Description: TODO(用一句话描述该文件做什么)
* @author: liandy
* @date: 2019年7月26日 下午10:27:15
* @version V1.0
*/
package com.kamfu.servlet; import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map; import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import com.caucho.hessian.io.SerializerFactory;
import com.caucho.hessian.server.HessianSkeleton;
import com.caucho.services.server.ServiceContext;
import com.kamfu.annotation.Service;
import com.kamfu.util.ClassUtil; /**
* @ClassName: HessianServlet
* @Description:Servlet for serving Hessian services.
* @author: liandy
* @date: 2019年7月26日 下午10:27:15
*
*/
@SuppressWarnings("serial")
public class HessianServlet extends HttpServlet { private Map<String, Object> serviceImplCache = Collections.synchronizedMap(new HashMap<String, Object>());
private Map<String, Class<?>> serviceAPICache = Collections.synchronizedMap(new HashMap<String, Class<?>>());
private SerializerFactory _serializerFactory; public void service(ServletRequest request, ServletResponse response) throws IOException, ServletException { // logger.debug("Hessian服务调用开始");
HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponse res = (HttpServletResponse) response;
if (!req.getMethod().equals("POST")) {
// res.setStatus(500); // , "Hessian Requires POST");
PrintWriter out = res.getWriter(); res.setContentType("text/html");
out.println("<h1>Hessian Requires POST</h1>");
out.close(); return;
} String serviceId = req.getPathInfo();
HessianSkeleton _homeSkeleton = getHomeSkeleton(serviceId); String objectId = req.getParameter("id");
if (objectId == null)
objectId = req.getParameter("ejbid"); ServiceContext.begin(req, res, serviceId, objectId); try {
InputStream is = request.getInputStream();
OutputStream os = response.getOutputStream(); response.setContentType("x-application/hessian"); SerializerFactory serializerFactory = getSerializerFactory();
invoke(_homeSkeleton, is, os, objectId, serializerFactory); } catch (Throwable e) { throw new ServletException(e);
} finally {
ServiceContext.end();
}
// logger.debug("Hessian服务调用结束");
}
/**
* Sets the serializer factory.
*/
public void setSerializerFactory(SerializerFactory factory) {
_serializerFactory = factory;
} /**
* Gets the serializer factory.
*/
public SerializerFactory getSerializerFactory() {
if (_serializerFactory == null)
_serializerFactory = new SerializerFactory(); return _serializerFactory;
} /**
* Sets the serializer send collection java type.
*/
public void setSendCollectionType(boolean sendType) {
getSerializerFactory().setSendCollectionType(sendType);
} /**
* Sets the debugging flag.
*/
public void setDebug(boolean isDebug) {
} /**
* Sets the debugging log name.
*/
public void setLogName(String name) {
// _log = Logger.getLogger(name);
} /**
* <p>Title: init</p>
* <p>Description: 初始化</p>
* @param config
* @throws ServletException
* @see javax.servlet.GenericServlet#init(javax.servlet.ServletConfig)
*/
public void init(ServletConfig config) throws ServletException { super.init(config);
try { this.registerRemoteService(); if ("true".equals(getInitParameter("debug"))) {
} if ("false".equals(getInitParameter("send-collection-type")))
setSendCollectionType(false);
} catch (Throwable e) {
// TODO PAO: 此处考虑如何处理Serverlet异常
throw new ServletException(e);
}
} /**
* @Title: registerRemoteService
* @Description: 注册远端服务
* @param: @throws IOException
* @param: @throws ClassNotFoundException
* @param: @throws InstantiationException
* @param: @throws IllegalAccessException
* @return: void
* @throws
*/
private void registerRemoteService()
throws IOException, ClassNotFoundException, InstantiationException, IllegalAccessException {
for (Class<?> c : ClassUtil.getAnnotationClassList("com.kamfu.service", Service.class)) {
Class<?>[] interfaces = c.getInterfaces();
if (interfaces != null && interfaces.length > 0) {
this.serviceImplCache.put(c.getSimpleName(), c.newInstance());
this.serviceAPICache.put(c.getSimpleName(), interfaces[0]);
} } }
/**
* Invoke the object with the request from the input stream.
*
* @param in the Hessian input stream
* @param out the Hessian output stream
*/
protected void invoke(HessianSkeleton skeleton, InputStream is, OutputStream os, String objectId,
SerializerFactory serializerFactory) throws Exception {
skeleton.invoke(is, os, serializerFactory);
} private HessianSkeleton getHomeSkeleton(String serviceId) throws ServletException { String sId = (serviceId != null && serviceId.startsWith("/")) ? serviceId.substring(1) : serviceId;
Class<?> _homeAPI = this.getHomeAPI(sId); Object _homeImpl = this.getHomeImpl(sId);
HessianSkeleton _homeSkeleton = new HessianSkeleton(_homeImpl, _homeAPI);
return _homeSkeleton;
} private Class<?> getHomeAPI(String sId) { return this.serviceAPICache.get(sId);
} private Object getHomeImpl(String sId) { return this.serviceImplCache.get(sId);
}
}
HessianServlet
核心代码:通过服务的实例化对象及服务的接口实例化 HessianSkeleton对象。
6)maven配置
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>WebServer</groupId>
<artifactId>WebServer</artifactId>
<version>0.0.1</version>
<packaging>war</packaging>
<build>
<sourceDirectory>src</sourceDirectory>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.0</version>
<configuration>
<source>1.6</source>
<target>1.6</target>
</configuration>
</plugin>
<plugin>
<artifactId>maven-war-plugin</artifactId>
<version>3.2.1</version>
<configuration>
<warSourceDirectory>WebContent</warSourceDirectory>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>hessian</groupId>
<artifactId>hessian</artifactId>
<version>4.0.37</version>
</dependency>
<!-- <dependency> -->
<!-- <groupId>com.kamfu.lib</groupId> -->
<!-- <artifactId>Library</artifactId> -->
<!-- <version>0.0.1</version> -->
<!-- </dependency> -->
</dependencies>
</project>
pom.xml
7)web应用配置
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0">
<display-name>WebServer</display-name>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list> <servlet>
<!-- 配置 HessianServlet,Servlet的名字随便配置,例如这里配置成ServiceServlet-->
<servlet-name>ServiceServlet</servlet-name>
<servlet-class>com.kamfu.servlet.HessianServlet</servlet-class> <!-- 配置接口的具体实现类 -->
<!-- <init-param> -->
<!-- <param-name>service-class</param-name> -->
<!-- <param-value>com.kamfu.service.BaseService</param-value> -->
<!-- </init-param> -->
</servlet>
<!-- 映射 HessianServlet的访问URL地址-->
<servlet-mapping>
<servlet-name>ServiceServlet</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
</web-app>
web.xml
2、创建客户端Client(Java project)转成maven
1)客户端调用
package com.kamfu.client; import com.caucho.hessian.client.HessianProxyFactory;
import com.kamfu.service.IBaseService; /**
* Hello world!
*
*/
public class App
{
public static void main( String[] args )
{
try {
String url = "http://localhost:8080/WebServer/BaseService";
HessianProxyFactory factory = new HessianProxyFactory();
factory.setOverloadEnabled(true);
IBaseService basic = (IBaseService) factory.create(IBaseService.class, url);
System.out.println(basic.test());
}catch (Exception e){
e.printStackTrace();
} }
}
App
2)maven配置
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion> <groupId>com.kamfu.client</groupId>
<artifactId>Client</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging> <name>Client</name>
<url>http://maven.apache.org</url> <properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties> <dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>WebServer</groupId>
<artifactId>WebServer</artifactId>
<version>0.0.1</version>
</dependency>
</dependencies>
</project>
pom.xml
3)客户端从服务端接收到的数据
六、原理图
Hession实现远程通讯(基于Binary-RPC协议)的更多相关文章
- 基于二进制RPC协议法的轻量级远程调用框架 ---- Hessian
使用Java创建Hessian服务有四个步骤: 1.创建Java接口作为公共API (client和server端 创建一个相同的借口) 2.使 ...
- 网络协议 21 - RPC 协议(中)- 基于 JSON 的 RESTful 接口协议
上一节我们了解了基于 XML 的 SOAP 协议,SOAP 的 S 是啥意思来着?是 Simple,但是好像一点儿都不简单啊! 传输协议问题 对于 SOAP 来讲,比如我创建一个订单, ...
- 网络协议 20 - RPC 协议(上)- 基于XML的SOAP协议
[前五篇]系列文章传送门: 网络协议 15 - P2P 协议:小种子大学问 网络协议 16 - DNS 协议:网络世界的地址簿 网络协议 17 - HTTPDNS:私人定制的 DNS 服务 网络协议 ...
- 基于Socket通讯(C#)和WebSocket协议(net)编写的两种聊天功能(文末附源码下载地址)
今天我们来盘一盘Socket通讯和WebSocket协议在即时通讯的小应用——聊天. 理论大家估计都知道得差不多了,小编也通过查阅各种资料对理论知识进行了充电,发现好多demo似懂非懂,拷贝回来又运行 ...
- Java 远程通讯技术及原理分析
在分布式服务框架中,一个最基础的问题就是远程服务是怎么通讯的,在Java领域中有很多可实现远程通讯的技术,例如:RMI.MINA.ESB.Burlap.Hessian.SOAP.EJB和JMS等,这些 ...
- JAVA与.NET的相互调用——利用JNBridge桥接模式实现远程通讯
分布式开发的历史 利用Remote方式调用远程对象实现服务器与客户端之间通讯是一种常用的网络开发方式,在.NET与JAVA开发当中,对Remote远程对象早已有着足够的支持(对Remote远程对象调用 ...
- 网络协议 22 - RPC 协议(下)- 二进制类 RPC 协议
前面我们认识了两个常用文本类的 RPC 协议,对于陌生人之间的沟通,用 NBA.CBA 这样的缩略语,会使得协议约定非常不方便. 在讲 CDN 和 DNS 的时候,我们讲过接入层的设计 ...
- JAVA 远程通讯机制
在分布式服务框架中,一个最基础的问题就是远程服务是怎么通讯的,在Java领域中有很多可实现远程通讯的技术,例如:RMI.MINA.ESB. Burlap.Hessian.SOAP.EJB和JMS等,这 ...
- Java远程通讯技术及原理分析
在分布式服务框架中,一个最基础的问题就是远程服务是怎么通讯的,在Java领域中有很多可实现远程通讯的技术,例如:RMI.MINA.ESB.Burlap.Hessian.SOAP.EJB和JMS等,这些 ...
随机推荐
- 【转】优秀的Vue UI组件库
原文来源:https://www.leixuesong.com/3342 Vue 是一个轻巧.高性能.可组件化的MVVM库,API简洁明了,上手快.从Vue推出以来,得到众多Web开发者的认可.在公司 ...
- js 数组、字符串、Json互相转换
arr.join(): 数组转字符串 let arr = [1,2,3,4]; let str = arr.join(','); arr.split():字符串转数组 let str = '1,2,3 ...
- day13 python生成器函数 推导式 生成器
day13 python 一.生成器 生成器的本质就是迭代器 生成器的特点和迭代器一样. 取值方式和迭代器一样(__next__()) 由生成器函数或生成器表达式来创建 ...
- python基础--逻辑运算
#and or not#and 且 :两边都为真才是真#or 或:一个真就是真(一真为真)#ont 非:相反#优先级:1.not>and>or#同一优先级由左向右以此计算!#列子:prin ...
- spring需要表
DROP TABLE IF EXISTS `user`;CREATE TABLE `user` ( `id` int(11) NOT NULL AUTO_INCREMENT, `username` ...
- java.sql.SQLException: Illegal mix of collations (utf8mb4_general_ci,IMPLICIT) and (utf8mb4_0900_ai_ci,IMPLICIT) for operation '='
查询视图时报错:java.sql.SQLException: Illegal mix of collations (utf8mb4_general_ci,IMPLICIT) and (utf8mb4_ ...
- Ceph介绍及原理架构分享
https://www.jianshu.com/p/cc3ece850433 1. Ceph架构简介及使用场景介绍 1.1 Ceph简介 Ceph是一个统一的分布式存储系统,设计初衷是提供较好的性能. ...
- epoll学习(二)
首先看程序一,这个程序想要实现的功能是当用户从控制台有任何输入操作时,输出”hello world!”. l 程序一 #include <unistd.h> #include <io ...
- winserver安装zabbixAgent
zabbix 布署实践[8 监控windows server] 参考http://www.cnblogs.com/likehua/p/3968689.html的思路,我安装的是zabbix 3.0 ...
- VIEW当中自定义属性的使用
主要有三种方法可以实现自定义属性. 第一种方法,直接设置属性值,通过attrs.getAttributeResourceValue拿到这个属性值. (1)在xml文件中设置属性值 [html] vie ...