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>      
     * @throws   
     */
    public static List> getAnnotationClassList(String packageName,Class annotationClass) throws IOException, ClassNotFoundException
    {
        List> result=new ArrayList>();
        List> 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> getAllAssignedClass(Class cls) throws IOException, ClassNotFoundException {
        List> classes = new ArrayList>();
        for (Class c : getClasses(cls)) {
            if (cls.isAssignableFrom(c) && !cls.equals(c)) {
                classes.add(c);
            }
        }
        return classes;
    }
    public static List> getAllAssignedClass(Class cls,String packageName) throws IOException, ClassNotFoundException {
        List> classes = new ArrayList>();
        for (Class c : scanPackage(packageName)) {
            if (cls.isAssignableFrom(c) && !cls.equals(c)) {
                classes.add(c);
            }
        }
        return classes;
    }
    
    public static List> 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> 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> getClasses(File dir, String pk) throws ClassNotFoundException {
        List> classes = new ArrayList>();
        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{

    /**   
     * 

Title: test

*

Description:

*
@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 serviceImplCache = Collections.synchronizedMap(new HashMap());
    private Map> serviceAPICache = Collections.synchronizedMap(new HashMap>());
    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("

Hessian Requires POST

"); 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); } /** *

Title: init

*

Description: 初始化

*
@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配置


  4.0.0
  WebServer
  WebServer
  0.0.1
  war
  
    src
    
      
        maven-compiler-plugin
        3.8.0
        
          1.6
          1.6
        
      
      
        maven-war-plugin
        3.2.1
        
          WebContent
        
      
    
  
  
    
        hessian
        hessian
        4.0.37
      





  
pom.xml

  7)web应用配置



  WebServer
    
        index.jsp
    

    
        
        ServiceServlet
        class>com.kamfu.servlet.HessianServletclass>
        
        




    
    
    
        ServiceServlet
        /*
    
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配置  


  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  4.0.0

  com.kamfu.client
  Client
  0.0.1-SNAPSHOT
  jar

  Client
  http://maven.apache.org

  
    UTF-8
  

  
    
      junit
      junit
      3.8.1
      test
    
       
        WebServer
        WebServer
        0.0.1
    
  
pom.xml

  3)客户端从服务端接收到的数据

  Hession实现远程通讯(基于Binary-RPC协议)_第1张图片

 

六、原理图

Hession实现远程通讯(基于Binary-RPC协议)_第2张图片

 

转载于:https://www.cnblogs.com/liandy001/p/11253643.html

你可能感兴趣的:(Hession实现远程通讯(基于Binary-RPC协议))