1. 程式人生 > >Hessian遠端呼叫框架進階教程(一) Hessian介紹JAVA使用Hessian進行程式設計例項

Hessian遠端呼叫框架進階教程(一) Hessian介紹JAVA使用Hessian進行程式設計例項

Hessian介紹

Dubbo提供了RPC服務、服務治理,而Spring Cloud則涵蓋了微服務的方方面面,服務治理只是其中的一個方面,關於二者的比較,可以參看程式猿DD的一篇部落格–微服務架構的基礎框架選擇:Spring Cloud還是Dubbo?。儘管國內大部分互初創聯網公司幾乎是用Zookeeper+Dubbo搭建的架構,而Spring Cloud商用成熟產品少之又少,但是筆者個人覺得未來短時間之內Spring Cloud必火,各位不要錯過了。轉入正題,我們已經有了Dubbo、Spring Cloud為什麼還要了解Hessian呢?因為

  • Hessian很簡單,理解其使用和機制之後,有助於你理解其他微服務框架(這是重點,本教程理解的越深越細,對學習微服務框架幫助越大這也是我們所期望的)
  • Hessian是基於 Http 協議進行傳輸的,初中級程式猿都很熟悉的通訊協議
  • Hessian是一種RPC框架,就是遠端方法呼叫,一個服務中某個類可以呼叫其他服務的某個類的某個方法

那麼接下來就好理解了,Hessian是一個使用Http協議進行遠端方法呼叫的框架。
使用Http協議,必須有一個Web服務(Hessian服務端或者叫提供者–dubbo的叫法);
應用端亦即消費端通過方法呼叫的形式獲得代理物件,呼叫服務端的介面實現方法;
應用端和服務端都需要持有公共服務的介面資訊;

使用hessian需要引入依賴:

<!-- 引入hessian依賴 -->
    <dependency
>
<groupId>com.caucho</groupId> <artifactId>hessian</artifactId> <version>4.0.38</version> </dependency>

我們以一個簡單的例子入門:獲取一個使用者的資訊。

  • 公共服務介面類:中間工程jar包middleProject,僅僅包含hello方法和一個重新設定使用者年齡的方法。
  • 服務端:構建成一個web服務,只有一個介面實現類需要依賴middleProject,需要配置成hessian服務。
  • 客戶端:同樣依賴middleProject,使用hessian代理工廠例項化公共介面服務類,然後呼叫該例項的方法。

公共介面服務(打包成jar,讓服務端、client端都需要依賴)

該介面定義了兩個簡單方法:

  • helloWorld方法,返回一個簡單字串
  • getMyInfo方法,傳入一個複雜物件,並重新設定其age屬性,再將新的user物件返回給client端。

HelloService.java

package org.byron4j.hessian.service;

import org.byron4j.hessian.entity.User;

/**
 *  @author     Byron.Y.Y
 *  @optDate    2016年12月6日
 *  This class is for ...
 */
public interface HelloService {

    public String helloWorld(String message);

    public User getMyInfo(User user);

}

使用者類是一個簡單的POJO,需要實現Serializable介面以序列化
User.java

package org.byron4j.hessian.entity;

import java.io.Serializable;
import java.util.Map;

/**
 *  @author     Byron.Y.Y
 *  @optDate    2016年12月6日
 *  This class is for ...
 */
public class User implements Serializable{


    /**
     * 
     */
    private static final long serialVersionUID = -1352128884522619903L;

    private String userName;

    private int age;

    private Map<String, Object> detailData;

    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public Map<String, Object> getDetailData() {
        return detailData;
    }

    public void setDetailData(Map<String, Object> detailData) {
        this.detailData = detailData;
    }

}

公共服務需要打包成jar包,hessian服務端、client端都需要依賴該jar;或者使用maven構建的話將公共服務需要打包成jardeploy到私服中,hessian服務端、client端都通過maven座標引入依賴(本系列文章採取的方式)。

Hessian服務端

服務端必須暴露服務,我們將其發構建成一個web服務,在web.xml中配置指定hessian服務的介面以及具體的實現服務、servlet;該工程只有一個實現HelloService介面的類HelloServiceImpl並且繼承自HessianServlet。

HelloServiceImpl.java

package org.byron4j.hessian.service.impl;

import org.byron4j.hessian.entity.User;
import org.byron4j.hessian.service.HelloService;

import com.caucho.hessian.server.HessianServlet;

/**
 *  @author     Byron.Y.Y
 *  @optDate    2016年12月6日
 *  
 */
public class HelloServiceImpl extends HessianServlet  implements HelloService{

    /**
     * 
     */
    private static final long serialVersionUID = -3537274030227675984L;

    @Override
    public String helloWorld(String message) {
        return "Hello, " + message;
    }

    @Override
    public User getMyInfo(User user) {
        if(null == user){ return new User(); }

        user.setAge(99);
        return user;
    }


}

web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.0" xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"> 
    <display-name>hessian-showcase</display-name>

    <welcome-file-list>
        <welcome-file>index.jsp</welcome-file>
    </welcome-file-list>

    <servlet>
        <servlet-name>hessian-service</servlet-name>

        <servlet-class>
            com.caucho.hessian.server.HessianServlet
        </servlet-class>

        <init-param>            
            <param-name>home-class</param-name>            
            <param-value>
                <!-- 服務實現類 -->
                org.byron4j.hessian.service.impl.HelloServiceImpl
            </param-value>
        </init-param>

        <init-param>            
            <param-name>home-api</param-name>
            <!-- 服務介面 -->
            <param-value>
                org.byron4j.hessian.service.HelloService
            </param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>

    <servlet-mapping>
        <servlet-name>hessian-service</servlet-name>
        <url-pattern>/hessian</url-pattern>
    </servlet-mapping>

</web-app>

pom.xml

<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>org.byron4j</groupId>
  <artifactId>hessian</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <packaging>war</packaging>

  <name>hessian</name>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  </properties>

  <dependencies>

    <!-- 引入hessian依賴 -->
    <dependency>
      <groupId>com.caucho</groupId>
      <artifactId>hessian</artifactId>
      <version>4.0.38</version>
    </dependency>

    <!-- 引入介面服務定義(公共服務介面jar包) -->
    <dependency>
     <groupId>org.byron4j</groupId>
     <artifactId>hessianMiddleJar</artifactId>
     <version>0.0.1-SNAPSHOT</version>
   </dependency>

    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.12</version>
      <scope>test</scope>
    </dependency>

    <!-- 引入servlet -->
    <dependency>
        <groupId>javax.servlet</groupId>
        <artifactId>servlet-api</artifactId>
        <version>3.0-alpha-1</version>
    </dependency>
  </dependencies>

  <build>
    <finalName>hessionDemo</finalName>


    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>3.5.1</version>
            <configuration>
                <source>1.8</source>
                <target>1.8</target>
            </configuration>
        </plugin>
    </plugins>
  </build>
</project>

Hessian Client端

client端同樣需要依賴公共服務jar,該專案只有一個單元測試類HessianClient。使用HessianProxyFactory建立介面服務

HessianProxyFactory factory = new HessianProxyFactory();
HelloService helloService = (HelloService) factory.create(HelloService.class, url);
helloService.helloWorld("kitty!")

HessianClient.java

package org.byron4j.hessionClient;

import java.net.MalformedURLException;
import java.util.HashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import org.byron4j.hessian.entity.User;
import org.byron4j.hessian.service.HelloService;
import org.junit.Test;

import com.caucho.hessian.client.HessianProxyFactory;

/**
 * Hello world!
 *
 */
public class HessianClient 
{
    static ExecutorService es =  Executors.newFixedThreadPool(10);
    /**
     * 測試hessian服務是否可用,並要求在2秒內獲得響應
     * @throws MalformedURLException
     */
    @Test//(timeout = 2000)
    public void testService4Success() throws MalformedURLException {        

        String url = "http://localhost:8080/hessionDemo/hessian";
        System.out.println("請求的服務端地址:" + url);

        HessianProxyFactory factory = new HessianProxyFactory();
        HelloService helloService = (HelloService) factory.create(HelloService.class, url);
        System.out.println("服務端返回結果為:" + helloService.helloWorld("kitty!"));


        HashMap<String, Object> detailData = new HashMap<String, Object>();
        detailData.put("isMarried", "N");
        detailData.put("gender", "F");

        User user = new User();
        user.setAge(18);
        user.setUserName("OYY");
        user.setDetailData(detailData);

        int time = 100000;
        long startTime = System.currentTimeMillis();
        for(int i = 0; i< time; i++){
            es.execute(new Runnable() {

                @Override
                public void run() {
                    helloService.getMyInfo(user);
                }
            });

        }

        System.out.println(time + "次呼叫耗時:" + (System.currentTimeMillis() - startTime));
        System.out.println("+--獲得複雜物件:" );
        System.out.println("      +--新年齡:" + helloService.getMyInfo(user).getAge());
        System.out.println("      +--隱私資訊:" + helloService.getMyInfo(user).getDetailData());

    }
}

pom.xml

<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>org.byron4j</groupId>
  <artifactId>hessionClient</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <packaging>jar</packaging>

  <name>hessionClient</name>
  <url>http://maven.apache.org</url>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  </properties>

  <dependencies>
    <!-- 引入hessian依賴 -->
    <dependency>
      <groupId>com.caucho</groupId>
      <artifactId>hessian</artifactId>
      <version>4.0.38</version>
    </dependency>

    <!-- 引入介面服務定義(公共服務介面jar包) -->
    <dependency>
     <groupId>org.byron4j</groupId>
     <artifactId>hessianMiddleJar</artifactId>
     <version>0.0.1-SNAPSHOT</version>
   </dependency>

    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.12</version>
      <scope>test</scope>
    </dependency>
  </dependencies>

  <build>
    <finalName>hessionClientDemo</finalName>

    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>3.5.1</version>
            <configuration>
                <source>1.8</source>
                <target>1.8</target>
            </configuration>
        </plugin>
    </plugins>
  </build>
</project>

例項執行結果

執行client單元測試結果如下,本例項還增加了一個執行緒例項用於測試單執行緒高訪問量、多執行緒多訪問量使用hessian RMI呼叫的時間。

請求的服務端地址:http://localhost:8080/hessionDemo/hessian
服務端返回結果為:Hello, kitty!
100000次呼叫耗時:33
+--獲得複雜物件:
      +--新年齡:99
      +--隱私資訊:{isMarried=N, gender=F}

原始碼下載