• hessian学习笔记


    一、hessian是什么

    Hessian是一个轻量级的remoting onhttp工具,使用简单的方法提供了RMI的功能。 相比WebService,Hessian更简单、快捷。采用的是二进制RPC协议,因为采用的是二进制协议,所以它很适合于发送二进制数据。——百度百科

    学习hessian,必须知道什么是RPC

    实现RPC,必须解决如下几个问题:

    1、通讯问题。

    2、寻址问题。

    3、序列化与反序列化。

    带着这三个问题我们一起来探究一下hessian;

    二、hessian怎么使用

    首先,大家去下载源码,并导入到idea中打开;

    https://github.com/zhaojiatao/learn_hessian

    项目结构:

    --learn_hessian

    ----api  客户端和服务端均共同引用的接口api

    ----client  客户端调用demo,包括本地直接通过代理对象调用以及使用spring集成方式调用

    ----webserver  通过传统servlet方式提供服务

    ----webserver_spring  与spring集成 提供服务

    2.1服务端搭建:

    2.1.1传统serlet方式搭建

    在web.xml中配置HessianServlet,

    指明服务地址:/hessian

    及其实现类:com.zjt.learn.hessian.api.impl.GetUserInfoImpl

    <servlet>
        <servlet-name>HessianServlet</servlet-name>
        <servlet-class>com.caucho.hessian.server.HessianServlet</servlet-class>
        <init-param>
          <param-name>service-class</param-name>
          <param-value>com.zjt.learn.hessian.api.impl.GetUserInfoImpl</param-value>
        </init-param>
      </servlet>
    
      <servlet-mapping>
        <servlet-name>HessianServlet</servlet-name>
        <url-pattern>/hessian</url-pattern>
      </servlet-mapping>
    package com.zjt.learn.hessian.api.impl;
    
    import com.zjt.learn.hessian.api.GetUserInfo;
    import com.zjt.learn.hessian.dto.User;
    import org.apache.commons.lang3.StringUtils;
    
    /**
     * Created by zhaojiatao@souche.com on 2018/4/17
     */
    public class GetUserInfoImpl implements GetUserInfo {
        @Override
        public String getuserinfo(String id) {
    
            if(StringUtils.isNotBlank(id)){
                User user=new User();
                user.setId("1");
                user.setName("zhaojiatao");
                user.setAddress("hangzhou");
                user.setAge(18);
                user.setGender(1);
                return user.toString();
            }
    
            return null;
        }
    }

    2.1.2使用spring方式集成发布服务

    首先在web.xml中配置springmvc:

    <servlet>
        <servlet-name>SpringMVC</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
          <param-name>contextConfigLocation</param-name>
          <param-value>classpath:applicationContext.xml</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
      </servlet>
    
      <servlet-mapping>
        <servlet-name>SpringMVC</servlet-name>
        <url-pattern>/remote/*</url-pattern>
      </servlet-mapping>

    配置applicationContext.xml:

    使用HessianServiceExporter来处理请求;

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans-4.1.xsd"
           default-lazy-init="true">
    
        <bean id = "getuserService" class="com.zjt.learn.hessian.api.impl.GetUserInfoImpl"/>
    
        <bean name="/getuserHessianService" class="org.springframework.remoting.caucho.HessianServiceExporter">
            <property name="service" ref="getuserService"/>
            <property name="serviceInterface" value="com.zjt.learn.hessian.api.GetUserInfo"/>
        </bean>
    </beans>

    2.2客户端调用

    2.2.1使用传统方式调用远程服务

    package test;
    
    import com.caucho.hessian.client.HessianProxyFactory;
    import com.zjt.learn.hessian.api.GetUserInfo;
    
    /**
     * Created by zhaojiatao@souche.com on 2018/4/17
     */
    public class BasicClient {
    
        public static void main(String[] args) {
            try {
                String url = "http://localhost:8080/hessian";
                HessianProxyFactory factory = new HessianProxyFactory();
                factory.setOverloadEnabled(true);
                GetUserInfo getUserInfo = (GetUserInfo) factory.create(GetUserInfo.class, url);
                System.out.println(getUserInfo.getuserinfo("1"));
                System.out.println("over");
            }catch (Exception e){
                e.printStackTrace();
            }
        }
    
    
    
    
    }

    2.2.2使用spring方式调用

    新建spring.xml配置文件

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans-4.1.xsd"
           default-lazy-init="true">
    
    
        <bean id="getuserService" class="org.springframework.remoting.caucho.HessianProxyFactoryBean">
            <property name="serviceUrl" value="http://localhost:8080/remote/getuserHessianService"/>
            <property name="serviceInterface" value="com.zjt.learn.hessian.api.GetUserInfo"/>
        </bean>
    </beans>
    package test;
    
    import com.zjt.learn.hessian.api.GetUserInfo;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    
    /**
     * Created by zhaojiatao@souche.com on 2018/4/18
     */
    public class BasicSpringClient {
    
    
        public static void main(String[] args) {
            ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(new String[]{"classpath:spring.xml"});
            GetUserInfo getUserInfo = (GetUserInfo)context.getBean("getuserService");
            System.out.println(getUserInfo.getuserinfo("1"));
        }
    
    
    }

    hessian的使用是很简单的。大家自己照着代码敲一下就可以。

    三、探究一下hessian的细节

    回到文章开始提出的问题,即rpc框架需要解决的问题,看看hessian如何解决的。

    3.1.通讯问题:

    我们先看看客户端在发起远程请求前都经历了什么:

    首先,客户端通过代理工厂对象HessianProxyFactory的create方法创建代理对象;

    在create方法里可以看到,该代理对象在执行时的handler是通过HessianProxy代理对象的invoke方法来执行;典型的动态代理;

     在invoke方法中:

    通过String methodName = method.getName();得到方法名

    通过sendRequest方法取得和服务端的连接HessianConnection对象;

    跟踪sendRequest方法,我们发现:

    发现hessian是使用http协议进行网络通信;

     在is = getInputStream(conn);处等待服务端返回的响应;

     3.2 寻址问题

    我们跟踪这里:

    我们得出结论:hessian使用lookup方法来寻找远程服务;

    3.3序列化与反序列化

    我们继续看刚刚跟踪的客户端调用时执行的HessianProxy对象的invoke方法,

    进入其中的

    conn = sendRequest(mangleName, args);

    再进入

    out.call(methodName, args);

    再进入

    writeObject(args[i]);

     进入其Hessian2Output实现中

    最终看到了hessian如何进行序列化:

    serializer.writeObject(object, this);

    至此,我们也可以梳理一下hessian客户端动态代理的执行流程:

    我们再来看看服务端的执行细节:

    通过后台的代码,可见我们所有的工作都围绕在HessianServlet在展开。该Servlet中有两个比较重要的方法:init()、service();

    init方法初始化服务和服务对象,主要分为3步:

    通过home-class或者service-class创建服务端的实现类实例;

    init方法还会创建HessianSkeleton对象,这是Hessian服务端的核心功能部分。

    HessianSkeleton继承自AbstractSkeleton,其构造方法,将会从实现类中抽取方法和方法的Method对象,并且存储到_methodMap中。

    对于一个Servlet来说其service方法是对外提供服务的方法:

    最主要的是调用HessianSkeleton对象的invoke方法。注意,Servlet实例中有两个HessianSkeleton变量,分别是:_objectSkeleton和 _homeSkeleton,

    invoke方法:

    首先从HessianInput对象中获取到Method信息,获取到真正的service对象。

    根据反射机制,调用service对象的invoke方法,获取到返回值。

    最后调用HessianOutput对象将结果写回到调用方。

     

     本文参考:

    https://blog.csdn.net/sunwei_pyw/article/details/74002351

    https://www.cnblogs.com/happyday56/p/4268249.html

  • 相关阅读:
    12.14 Daily Scrum
    12.13 Daily Scrum
    12.12 Daily Scrum
    12.11 Daily Scrum
    12.10 Daily Scrum
    12.9 Daily Scrum
    12.8 Daily Scrum
    M1事后分析汇报以及总结
    alpa开发阶段团队贡献分
    第9周团队作业
  • 原文地址:https://www.cnblogs.com/zhaojiatao/p/8908335.html
Copyright © 2020-2023  润新知