X

Hessian的使用

hessian主要是用来做序列化和反序列化的,序列化后的对象可以存储(文件或者数据库中),需要使用的时候,再将它反序列化得到对象。常用的序列化协议有人也能看懂的json,Google的protoBuf以及hessian等等。今天要介绍的就是hessian的用法。
一、当然是他的主功能,序列化,我们新建一个对象,然后将这个对象序列化之后存储到文件,然后再从文件中读取序列化后的数据,通过hessian反序列化成对象。代码如

====序列化和反序列化=====

package hessian;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;

import com.caucho.hessian.io.Hessian2Input;
import com.caucho.hessian.io.Hessian2Output;
import top.huster.hessian.domain.TestObject;

public class HessianSerialization {

    public static void main(String[] args)  {
        TestObject testObject = new TestObject(1, "a", 12L);
        try {
            OutputStream os = new FileOutputStream("test.data");
            Hessian2Output out = new Hessian2Output(os);
            out.writeObject(testObject);
            out.flush();
            os.close();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {

        }
        try {
            InputStream is = new FileInputStream("test.data");
            Hessian2Input in = new Hessian2Input(is);
            TestObject obj = (TestObject)in.readObject(TestObject.class);
            is.close();
        } catch (Exception e) {

        }

    }
}
//=== TestObject ==== 即使是private域, 反序列化也能拿到值
package top.huster.hessian.domain;

import java.io.Serializable;

public class TestObject implements Serializable {

    private static final long serialVersionUID = 8948707708814774073L;
    public int count;
    public String name;
    private Long number;

    public TestObject(int count, String name, Long number) {
        this.count = count;
        this.name = name;
        this.number = number;
    }
}

总结: 即使你定义的对象属性是私有属性, 也能够成功恢复对象

二、 使用hessian来执行远程调用
RPC的调用实现方式有很多种,记得以前做php的时候,还给别人提供过一个webService的服务,那时候觉得写Java好像都是一批老程序员,不过Java也的确是很久了。
RPC的服务实现有很多,淘宝内部有一个HSF,他通过configserver解决了调用寻址的问题,开源的叫dubbo。今天要介绍的是使用hessian实现的远程调用。你可以像调本地方法一样调用远程的服务。实现非常简单,但是没有解决寻址的问题,寻址是使用域名来实现的。

  1. 首先定义一个接口
package top.huster.hessian;

public interface HelloWorldService {
     String hello();
}

 

  1. 在服务端实现这个接口
package top.huster.hessian;

public class HelloWorldServiceImpl implements HelloWorldService {

    @Override
    public String hello() {
        return "hello longan!";
    }
}

 

  1. 然后将这个服务注册出去, 因为我用的是spring boot所以我以bean的方式注册Servlet,你也可以通过配置web.xml的方式来实现
package top.huster.hessian;

import com.caucho.hessian.server.HessianServlet;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.ArrayList;
import java.util.List;

@Configuration
public class ServletRegistion {

    @Bean
    public ServletRegistrationBean servletRegistrationBean() {
        ServletRegistrationBean servletRegistrationBean = new ServletRegistrationBean();
        HessianServlet hessianServlet = new HessianServlet();
        hessianServlet.setHomeAPI(HelloWorldService.class);
        hessianServlet.setHome(new HelloWorldServiceImpl());
        servletRegistrationBean.setServlet(hessianServlet);
        List<String> urlMappings=new ArrayList<>();
        urlMappings.add("/hello");
        servletRegistrationBean.setUrlMappings(urlMappings);
        servletRegistrationBean.setName("hello");

        return servletRegistrationBean;
    }

    @Bean
    public ServletRegistrationBean servletRegistrationBean2() {
        ServletRegistrationBean servletRegistrationBean = new ServletRegistrationBean();
        HessianServlet hessianServlet = new HessianServlet();
        hessianServlet.setHomeAPI(FileUploadService.class);
        hessianServlet.setHome(new FileUploadServiceimpl());
        servletRegistrationBean.setServlet(hessianServlet);
        List<String> urlMappings=new ArrayList<>();
        urlMappings.add("/upload");
        servletRegistrationBean.setUrlMappings(urlMappings);
        servletRegistrationBean.setName("upload");
        return servletRegistrationBean;
    }
}

 

  1. 客户端来调用
package hessian;

import com.caucho.hessian.client.HessianProxyFactory;
import top.huster.hessian.HelloWorldService;

public class HessianClientTest {
    public static void main(String []args)
        throws Exception {
        String url = "http://localhost:8080/hello";

        HessianProxyFactory factory = new HessianProxyFactory();
        HelloWorldService basic = (HelloWorldService) factory.create(HelloWorldService.class, url);
        String result = basic.hello();
        System.out.println("Hello: " + result);
    }
}

 

总结: 当你执行client端代码的时候,返回了正确的字符,实际上执行的是远程服务器的代码

三、 使用hessian上传和下载文件

因为使用hessian可以很方便的实现远程调用,而他的数据是通过网络以二进制流的方式发送,所以可以很容易的实现大文件的上传和下载。

  1. 提供一个接口
package top.huster.hessian;

import java.io.InputStream;

public interface FileUploadService {
     void upload(String filename, InputStream inputStream);
}

 

  1. 他的实现
package top.huster.hessian;

import java.io.FileOutputStream;
import java.io.InputStream;

public class FileUploadServiceimpl implements FileUploadService{

    @Override
    public void upload(String filename, InputStream inputStream) {
        try {
            FileOutputStream fileOutputStream = new FileOutputStream(filename);
            byte[] bytes = new byte[1024];
            while (inputStream.read(bytes) != -1) {
                fileOutputStream.write(bytes);
            }

            inputStream.close();
            fileOutputStream.close();
            System.out.println("ok ......");
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
        }
    }
}

 

  1. 同样注册一个服务
package top.huster.hessian;

import com.caucho.hessian.server.HessianServlet;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.ArrayList;
import java.util.List;

@Configuration
public class ServletRegistion {

    @Bean
    public ServletRegistrationBean servletRegistrationBean() {
        ServletRegistrationBean servletRegistrationBean = new ServletRegistrationBean();
        HessianServlet hessianServlet = new HessianServlet();
        hessianServlet.setHomeAPI(HelloWorldService.class);
        hessianServlet.setHome(new HelloWorldServiceImpl());
        servletRegistrationBean.setServlet(hessianServlet);
        List<String> urlMappings=new ArrayList<>();
        urlMappings.add("/hello");
        servletRegistrationBean.setUrlMappings(urlMappings);
        servletRegistrationBean.setName("hello");

        return servletRegistrationBean;
    }

    @Bean
    public ServletRegistrationBean servletRegistrationBean2() {
        ServletRegistrationBean servletRegistrationBean = new ServletRegistrationBean();
        HessianServlet hessianServlet = new HessianServlet();
        hessianServlet.setHomeAPI(FileUploadService.class);
        hessianServlet.setHome(new FileUploadServiceimpl());
        servletRegistrationBean.setServlet(hessianServlet);
        List<String> urlMappings=new ArrayList<>();
        urlMappings.add("/upload");
        servletRegistrationBean.setUrlMappings(urlMappings);
        servletRegistrationBean.setName("upload");
        return servletRegistrationBean;
    }
}

 

  1. 客户端的上传代码
package hessian;

import java.io.FileInputStream;

import com.caucho.hessian.client.HessianProxyFactory;
import top.huster.hessian.FileUploadService;

public class FileUploadClient {

    public static void main(String[] args) throws Exception{
        String url = "http://localhost:8080/upload";
        HessianProxyFactory factory = new HessianProxyFactory();
        FileUploadService basic = (FileUploadService) factory.create(FileUploadService.class, url);
        FileInputStream inputStream = new FileInputStream("/Users/longan/Downloads/TPPSystem2017.key");
        basic.upload("abc", inputStream);
    }
}

 

总结: 测试速度还是很快的,因为是本地^_^!在这里踩了一个坑,由于spring boot的文档特别的模糊,虽然告诉你如何注册一个Servlet服务,但是并没有写的很详细。我在注册第二个Servlet服务的时候,怎么都无法成功。虽然我也知道注册多个Servlet需要return多个ServletRegistrationBean,但是依然不成功。最后看到参考文档里提到,注册多个的时候,一定要设置Servlet的名字,否则就会因为同名被覆盖掉,设置了name之后果然就好了。

好了,hessian的介绍就差不多了,后面的还有一个运行在applet上的就不演示了,可以去看他的官方文档。

发现一个好东西 Resin server-push servlet可以源源不断的往client端push数据,非常适合实时的日志展示。
在以往,我们日志的展示都是通过循环请求服务端,查看有没有最新的信息,而通过这个东西,可以在服务端有新信息的时候,主动的push到client端,是不是很神奇? 有空可以试试。

参考文档 :
http://www.jianshu.com/p/be2dafc8c644

Categories: Java学习
Tags: Hessian
龙安_任天兵: 不忘初心,方得始终!