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实现的远程调用。你可以像调本地方法一样调用远程的服务。实现非常简单,但是没有解决寻址的问题,寻址是使用域名来实现的。
- 首先定义一个接口
package top.huster.hessian;
public interface HelloWorldService {
String hello();
}
- 在服务端实现这个接口
package top.huster.hessian;
public class HelloWorldServiceImpl implements HelloWorldService {
@Override
public String hello() {
return "hello longan!";
}
}
- 然后将这个服务注册出去, 因为我用的是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 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 urlMappings=new ArrayList<>();
urlMappings.add("/upload");
servletRegistrationBean.setUrlMappings(urlMappings);
servletRegistrationBean.setName("upload");
return servletRegistrationBean;
}
}
- 客户端来调用
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可以很方便的实现远程调用,而他的数据是通过网络以二进制流的方式发送,所以可以很容易的实现大文件的上传和下载。
- 提供一个接口
package top.huster.hessian;
import java.io.InputStream;
public interface FileUploadService {
void upload(String filename, InputStream inputStream);
}
- 他的实现
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 {
}
}
}
- 同样注册一个服务
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 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 urlMappings=new ArrayList<>();
urlMappings.add("/upload");
servletRegistrationBean.setUrlMappings(urlMappings);
servletRegistrationBean.setName("upload");
return servletRegistrationBean;
}
}
- 客户端的上传代码
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