hessian學習筆記

1、hessian是什麼

Hessian是一個輕量級的remoting onhttp工具,使用簡單的方法提供了RMI的功能。 相比WebService,Hessian更簡單、快捷。採用的是二進制RPC協議,由於採用的是二進制協議,因此它很適合於發送二進制數據。——百度百科html

 

學習hessian,必須知道什麼是RPCgit

實現RPC,必須解決以下幾個問題:github

一、通信問題。web

二、尋址問題。spring

三、序列化與反序列化。apache

帶着這三個問題咱們一塊兒來探究一下hessian;api

 

2、hessian怎麼使用

首先,你們去下載源碼,並導入到idea中打開;網絡

https://github.com/zhaojiatao/learn_hessianmvc

項目結構:app

--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的使用是很簡單的。你們本身照着代碼敲一下就能夠。

 

3、探究一下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

相關文章
相關標籤/搜索