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等,这些 ...
随机推荐
- 如何从零搭建一个webpack+react+redux+react-redux的开发环境一入门
阅读本文章的时候,你要有一定的基础知识储备,简单的es6知识,模块化思想知识,js基础知识,node基础知识,react等 首先执行npm init,此时我的文件叫case; 下面安装一些需要的npm ...
- 【彩彩只能变身队(第七组)】Alpha版
演示总结 -by 彩彩只能变身组(第七组) Part one:功能简介 教师端——班级主页 教师端——创建班级 教师端——批改作业 教师端——作业上交情况 学生端——班级主页 学生端——作业上传 在开 ...
- Docker配置阿里云镜像加速pull
前言:默认Docker拉取镜像是从Docker Hub上拉取,但由于防火墙的原因,导致镜像下载非常慢.为了提高拉取镜像的速度,可以配置阿里镜像或是网易镜像加速,通过使用经验推荐配置阿里镜像. 申请个人 ...
- php递归无限分类、根据子类获取所有顶类
//递归无限分类树 public static function diGui($data, $pid) { $arr = collect([]); if (empty($data)) { return ...
- Cisco基础(六):配置目前网络环境、项目阶段练习
一.配置目前网络环境 目标: 一家新创建的IT公司,公司位于北京有80多台服务器 目前网络环境使用技术,通过端口映射技术将web服务器发布给Internet: 三层交换:汇聚接入层交换机 默认路由:实 ...
- paper 147:Deep Learning -- Face Data Augmentation(一)
1. 在深度学习中,当数据量不够大时候,常常采用下面4中方法: (1)人工增加训练集的大小. 通过平移, 翻转, 加噪声等方法从已有数据中创造出一批"新"的数据.也就是Data ...
- QC增加Test、Defect字段
QC--Tools--customization,在Project Entities中增加字段,在Project Lists中编辑Lookup List类型字段的指定值
- linux删除指定文件夹中某个文件除外的其他文件
# shopt -s extglob # rm -fr !(file1) 如果是多个要排除的,可以这样: # rm -rf !(file1|file2) 首先科普下shopt -s extglob B ...
- HTTP超详细总结
HTTP协议概述 HTTP协议是Hyper Text Transfer Protocol(超文本传输协议)的缩写,是用于从万维网(WWW:World Wide Web )服务器传输超文本到本地浏览器的 ...
- c++简单String类实现
#include <iostream> #include <string> using namespace std; class String { public: String ...