一、开发工具

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)客户端从服务端接收到的数据

  

六、原理图

最新文章

  1. Swift 备忘单和快速参考
  2. Sort Methods
  3. HTML总结
  4. 安装zabbix报错configure: error: libcurl library not found
  5. redis-cli -h xxxxx -p xxxx monitor 监控host为xxxx,端口为xxx,redis连接及读写操作
  6. ubuntu15.10 给解压版的eclipse安装桌面快捷方式
  7. POJ 1426 Find The Multiple --- BFS || DFS
  8. (转载)javascript函数作用域和提前声明
  9. php函数参数
  10. MySQL汇总数据
  11. Asp.net MVC + EF + Spring.Net 项目实践(四)
  12. 48、tensorflow入门二,线性模型的拟合
  13. (转载)VB6之鼠标移出事件
  14. 晓莲说-何不原创:如何通过jad把class批量反编译成java文件
  15. 公共的JS组件-告别CURD
  16. 第四章:Oracle12c 数据库在linux环境安装
  17. HIT2019春软件构造-&gt;重写hashCode()方法
  18. IIS Express服务器遇到400/503/IIS Express Error的解决办法
  19. luogu||P1776||宝物筛选||多重背包||dp||二进制优化
  20. fiddler 笔记-设置断点

热门文章

  1. MYSQL如何优化?
  2. const char *转化为char *的方法
  3. Python3.5-20190513-廖老师-自我笔记-函数式编程
  4. 【leetcode】995. Minimum Number of K Consecutive Bit Flips
  5. 【leetcode】989. Add to Array-Form of Integer
  6. magento 站内优化和站外优化详解
  7. c++ vector push_back对象的时候存起来的是拷贝[转]
  8. TableStore最佳实践:GEO索引打造店铺搜索系统
  9. C# Winform版批量压缩图片程序
  10. 61、Queueable接口