1、Remote Procedure Call
- RPC的主要目标是让构建分布式更容易,在提供强大的远程调用能力时不损失本地调用的语义简洁性。为实现该目标,RPC框架需要提供一种透明的调用机制,让使用者不必显示的区别本地调用和远程调用。
- RPC不是一个协议或者方法,它只是一个概念。是一个统称,重点在于方法调用(不支持对象的概念),具体实现甚至可以用RMI RestFul等去实现,但一般不用,因为RMI不能跨语言,而RestFul效率太低。
- RPC多用于服务器集群之间的通信
- 从单机到分布式->分布式通信->最基本的东西:二进制数据传输
- 动态代理是RPC的核心之一
- RPC和序列化是分不开的,因此产生了很多序列化框架
- RPC不仅可以选序列化框架,网络协议也是可以选择的
1.1 现在有哪些RPC框架?
- Dubbo:国内最早开源的 RPC 框架,由阿里巴巴公司开发并于 2011 年末对外开源,仅支持 Java 语言。
- Motan:微博内部使用的 RPC 框架,于 2016 年对外开源,仅支持 Java 语言。
- Tars:腾讯内部使用的 RPC 框架,于 2017 年对外开源,仅支持 C++ 语言。
- SpringCloud:国外 Pivotal 公司 2014 年对外开源的 RPC 框架,提供了丰富的生态组件。
- gRPC:Google 于 2015 年对外开源的跨语言 RPC 框架,支持多种语言。
- Thrift:最初是由 Facebook 开发的内部系统跨语言的 RPC 框架,2007 年贡献给了 Apache 基金,成为Apache 开源项目之一,支持多种语言。
1.2 RPC具体步骤?
- 服务消费者(client客户端)通过本地调用的方式调用服务。
- 客户端存根(client stub)接收到请求后负责将方法、入参等信息序列化(组装)成能够进行网络传输的消息
体。 - 客户端存根(client stub)找到远程的服务地址,并且将消息通过网络发送给服务端。
- 服务端存根(server stub)收到消息后进行解码(反序列化操作)。
- 服务端存根(server stub)根据解码结果调用本地的服务进行相关处理。
- 本地服务执行具体业务逻辑并将处理结果返回给服务端存根(server stub)。
- 服务端存根(server stub)将返回结果重新打包成消息(序列化)并通过网络发送至消费方。
- 客户端存根(client stub)接收到消息,并进行解码(反序列化)。
- 服务消费方得到最终结果。
2、RPC涉及的技术?
- 动态代理
生成Client Stub和Server Stub的时候需要用到java动态代理技术 - 序列化
在网络中,所有的数据都会被转换成字节进行传送,需要对这些参数进行序列化和反序列化操作,目前最主流高效的开源序列化框架有:Kryo、FastJson、Hessian、Protobuf等 - NIO通信
java提供了NIO的解决方案,可以采用Netty或者mina框架来解决NIO的数据传输问题。开源的RPC框架Dubbo就是采用NIO通信,集成支持netty、mina、grizzly - 服务注册中心
通过服务注册中心,让客户端的连接调用服务端所发布的服务。主流的注册中心组件有:Redis、Zookeeper、Consul、ETcd。Dubbo采用的是Zookeeper提供的服务注册与发现功能。 - 负载均衡
在高并发的场景下,需要多个节点或集群来提升整体吞吐能力 - 健康检查
健康检查包括:客户端心跳和服务端主动探测两种方式
3、RPC序列化框架的选型
- Hessian比JDK序列化快、而且序列化之后的长度更短。
- java自带的序列化方式Serializable接口,只支持Java代码,效率很低且所占空间比较大
- 因此在设计RPC框架时,可以选用一些其他的序列化框架,如Hessian等
3.1 JDK Serializable
- JDK Serializable是Java自带的序列化框架,我们只需要实现java.io.Serilizable或java.io.Externalizable接口,就可以使用java自带的序列化机制。
- 实现序列化接口只是表示该类能够被序列化或反序列化,还需要借助IO操作的ObjectInputStream和ObjectOutputStream对对象进行序列化和反序列化。
- 缺点:
- 只能支持Java语言,不能跨语言使用。
- 不好用,语法生硬
- 速度慢,序列化的字节数组长度比较长,所占空间大
3.2 FST序列化框架
- FST是完全兼容JDK序列化框架,它在序列化速度上能达到JDK的10倍,序列化结果只有JDK的1/3
- 语法及其简洁
- 序列化之后的开销也比JDK少
- 缺点:
1.FST同样是针对Java开发的序列化框架,因此也不能跨语言使用
3.3 Kryo序列化框架
- Kryo是一个快速有效的Java序列化框架,它依赖底层ASM库用于字节码的生成,因此有比较好的运行速度
- Kryo的目标就是提供一个序列化速度快、结果体积小、API简单易用的序列化框架
- Kryo支持自动深、浅拷贝,它是直接通过对象的深度拷贝,而不是对象->字节->对象的过程
- 语法比较简洁,API易用
- 缺点:
1.也是针对Java开发的,不具有跨语言特性
3.4 Protocol buffer
- Protocol buffer是一种语言中立、平台无关、可扩展的序列化框架,Protocol buffer相较于前面几种序列化框架而言,它是需要预先定义Schema的。
- ProtocolBuf设计之初的目标就是能够设计一款与语言无关的序列化框架,它目前支持Java/Python/C++/Go/C#等,通用性是很强的
- Protocol需要使用IDL来定义Schema描述文件,定义完描述文件之后,可以直接使用protoc来生成序列化与反序列代码,因此,只需要简单编写描述文件,就可以使用protobuf了。
- 缺点:
反序列化性能比Kryo和FST差些
3.5 Thrift序列化框架
- Thrift是由Facebook实现的一种高效的、支持多种语言的远程服务调用框架,即RPC,后来Facebook将Thrift开源到Apache。
- Thrift是一个RPC框架,但是由于Thrift提供了多语言之间的RPC服务,所以很多时候被用于序列化中。
- 使用Thrift实现序列化主要分为3步:创建thrift IDL文件、编译生成Java代码、使用TSerializer和TDeserializer进行序列化和反序列化。
- Thrift目前支持 C++、Java、Python、PHP、Ruby、 Erlang、Perl、Haskell、C#、Cocoa、JavaScript、Node.js、Smalltalk、OCaml、Delphi等语言
- Thrift在序列化和反序列化的时间开销总和上和protobuf差不多,protobuf在序列化时间上更占优势,而Thrift在反序列化上有自己的优势
3.6 Hessian序列化框架
- Hessian是caucho公司开发的轻量级RPC框架,它使用HTTP协议传输,使用Hessian二进制序列化。
- Hessian支持跨语言、高效的二进制序列化协议,被经常用于序列化框架。
- Hessian序列化使用简单
3.7 Avro序列化框架
- Avro是一个数据序列化框架,它是Apache Hadoop下的一个子项目。
- Avro在设计之初就用于支持数据密集型应用,很适合运城或本地大规模数据交换和存储
- Avro通过Schema定义数据结构,目前支持Java、C、C++、C#、Python、PHP和Ruby语言
- Avro对于动态语言无需生成代码,但对于Java这类静态语言,还是需要使用avro-tools.jar来编译生成Java代码。在Schema编写上,感觉相比Thrift、Protobuf更加复杂
3.8 开销的对比图
4/RPC框架的演进
- ①第一个版本
特点:通信代码与真正的业务代码混杂
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.net.Socket;
public class Client {
public static void main(String[] args) throws Exception
{
Socket s = new Socket("127.0.0.1",8888);
ByteArrayOutputStream baos = new ByteArrayOutputStream();//开辟一块字节数组内存空间
DataOutputStream dos = new DataOutputStream(baos);//操作数据的流
dos.writeInt(123);//写死了
//写数据
s.getOutputStream().write(baos.toByteArray());//传输ID给服务器
s.getOutputStream().flush();
//读数据
DataInputStream dis = new DataInputStream(s.getInputStream());
int id = dis.readInt();
String name = dis.readUTF();
User user = new User(name,id);
System.out.println(user);
dos.close();
s.close();
}
}
--------------------------------------------------------------------------------
package com.demo.rpc01;
import com.demo.IUSerService;
import com.demo.User;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
public class Server {
private static boolean running = true;
public static void main(String[] args) throws Exception
{
ServerSocket ss = new ServerSocket(8888);
while(running)
{
Socket s = ss.accept();//监听端口
process(s);//处理请求
s.close();//关闭连接
}
ss.close();
}
private static void process(Socket s) throws Exception
{
InputStream in = s.getInputStream();
OutputStream out = s.getOutputStream();
DataInputStream dis = new DataInputStream(in);
DataOutputStream dos = new DataOutputStream(out);
int id = dis.readInt();//读入ID
IUSerService serService = new USerServiceImpl();
User user = serService.getUSerById(id);
dos.writeInt(user.getId());
dos.writeUTF(user.getName());
dos.flush();
}
}
-----------------------------------------------------------------------------------
package com.demo.rpc01;
import com.demo.IUSerService;
import com.demo.User;
public class USerServiceImpl implements IUSerService {
@Override
public User getUSerById(Integer id) {
return new User("Alice",id);
}
}
- ②第二个版本
特点:将客户端通信代码封装成Stub,简化了客户端的使用
package com.demo.rpc02;
public class Client {
public static void main(String[] args) throws Exception
{
Stub stub = new Stub();
System.out.println(stub.getUserById(123));
}
}
-----------------------------------------------------------------------------------
package com.demo.rpc02;
import com.demo.IUSerService;
import com.demo.User;
import com.demo.rpc01.USerServiceImpl;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
public class Server {
private static boolean running = true;
public static void main(String[] args) throws Exception
{
ServerSocket ss = new ServerSocket(8888);
while(running)
{
Socket s = ss.accept();
process(s);
s.close();
}
ss.close();
}
private static void process(Socket s) throws Exception
{
InputStream in = s.getInputStream();
OutputStream out = s.getOutputStream();
DataInputStream dis = new DataInputStream(in);
DataOutputStream dos = new DataOutputStream(out);
int id = dis.readInt();
IUSerService serService = new USerServiceImpl();
User user = serService.getUSerById(id);
dos.writeInt(user.getId());
dos.writeUTF(user.getName());
dos.flush();
}
}
-----------------------------------------------------------------------------------
package com.demo.rpc02;
import com.demo.IUSerService;
import com.demo.User;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.net.Socket;
public class Stub {
public User getUserById(Integer id) throws Exception
{
Socket s = new Socket("127.0.0.1",8888);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
DataOutputStream dos = new DataOutputStream(baos);
dos.writeInt(123);
s.getOutputStream().write(baos.toByteArray());
s.getOutputStream().flush();
DataInputStream dis = new DataInputStream(s.getInputStream());
int receivedId = dis.readInt();
String name = dis.readUTF();
User user = new User(name,id);
dos.close();
s.close();
return user;
}
}
- ③第三个版本
特点:运用动态代理,将客户端通信代码放在代理方法中,但这时接口是写死的,只能处理IUserService的业务请求
package com.demo.rpc03;
import com.demo.IUSerService;
public class Client {
public static void main(String[] args) throws Exception
{
IUSerService stub = (IUSerService) Stub.getStub();
System.out.println(stub.getUSerById(123));
}
}
--------------------------------------------------------------------------------------------------
package com.demo.rpc03;
import com.demo.IUSerService;
import com.demo.User;
import com.demo.rpc01.USerServiceImpl;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
public class Server {
private static boolean running = true;
public static void main(String[] args) throws Exception
{
ServerSocket ss = new ServerSocket(8888);
while(running)
{
Socket s = ss.accept();
process(s);
s.close();
}
ss.close();
}
private static void process(Socket s) throws Exception
{
InputStream in = s.getInputStream();
OutputStream out = s.getOutputStream();
DataInputStream dis = new DataInputStream(in);
DataOutputStream dos = new DataOutputStream(out);
int id = dis.readInt();
IUSerService serService = new USerServiceImpl();
User user = serService.getUSerById(id);
dos.writeInt(user.getId());
dos.writeUTF(user.getName());
dos.flush();
}
}
------------------------------------------------------------------------------------------
package com.demo.rpc03;
import com.demo.IUSerService;
import com.demo.User;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.net.Socket;
public class Stub {
public static Object getStub(){
InvocationHandler h = new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Socket s = new Socket("127.0.0.1",8888);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
DataOutputStream dos = new DataOutputStream(baos);
dos.writeInt(123);
s.getOutputStream().write(baos.toByteArray());
s.getOutputStream().flush();
DataInputStream dis = new DataInputStream(s.getInputStream());
int id = dis.readInt();
String name = dis.readUTF();
User user = new User(name,id);
dos.close();
s.close();
return user;
}
};
Object o = Proxy.newProxyInstance(IUSerService.class.getClassLoader(),new Class[]{IUSerService.class},h);//生成代理类
return (IUSerService)o;
}
}
- ④第四个版本
特点:客户端向服务端传入需要调用的方法名,服务端在接收到之后,利用反射机制去调用对应方法,但服务端接口是写死的
package com.demo.rpc04;
import com.demo.IUSerService;
public class Client {
public static void main(String[] args) throws Exception
{
Object stub = Stub.getStub();
System.out.println(((IUSerService)stub).getUSerById(123));
}
}
--------------------------------------------------------------------------------------
package com.demo.rpc04;
import com.demo.IUSerService;
import com.demo.User;
import com.demo.rpc01.USerServiceImpl;
import java.io.*;
import java.lang.reflect.Method;
import java.net.ServerSocket;
import java.net.Socket;
public class Server {
private static boolean running = true;
public static void main(String[] args) throws Exception
{
ServerSocket ss = new ServerSocket(8888);
while(running)
{
Socket s = ss.accept();
process(s);
s.close();
}
ss.close();
}
private static void process(Socket s) throws Exception
{
InputStream in = s.getInputStream();
OutputStream out = s.getOutputStream();
DataInputStream dis = new DataInputStream(in);
DataOutputStream dos = new DataOutputStream(out);
ObjectInputStream oos = new ObjectInputStream(in);
String methodName = oos.readUTF();//读入方法名
Class[] parameterTypes = (Class[]) oos.readObject();//读入方法参数类型
Object[] args = (Object[]) oos.readObject();//读入方法参数
IUSerService serService = new USerServiceImpl();
Method method = serService.getClass().getMethod(methodName,parameterTypes);//调用方法
User user = (User)method.invoke(serService,args);
dos.writeInt(user.getId());
dos.writeUTF(user.getName());
dos.flush();
}
}
-------------------------------------------------------------------------------------------
package com.demo.rpc04;
import com.demo.IUSerService;
import com.demo.User;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.net.Socket;
public class Stub {
public static Object getStub(){
InvocationHandler h = new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Socket s = new Socket("127.0.0.1",8888);
ObjectOutputStream oos = new ObjectOutputStream(s.getOutputStream());
String methodName = method.getName();
Class[] parameterTypes = method.getParameterTypes();//获取参数类型数组,这是防止重载带来的错误
oos.writeUTF(methodName);
oos.writeObject(parameterTypes);
oos.writeObject(args);//方法参数
oos.flush();
DataInputStream dis = new DataInputStream(s.getInputStream());
int id = dis.readInt();
String name = dis.readUTF();
User user = new User(name,id);
oos.close();
s.close();
return user;
}
};
Object o = Proxy.newProxyInstance(IUSerService.class.getClassLoader(),new Class[]{IUSerService.class},h);//生成代理类
return o;
}
}
- ⑤第五个版本
特点:只把Stub的getStub的返回值换成了IUserService,在客户端不用强转了
package com.demo.rpc05;
import com.demo.IUSerService;
public class Client {
public static void main(String[] args) throws Exception
{
IUSerService stub = Stub.getStub();
System.out.println(stub.getUSerById(123));
}
}
---------------------------------------------------------------------------------------
package com.demo.rpc05;
import com.demo.IUSerService;
import com.demo.User;
import com.demo.rpc01.USerServiceImpl;
import java.io.*;
import java.lang.reflect.Method;
import java.net.ServerSocket;
import java.net.Socket;
public class Server {
private static boolean running = true;
public static void main(String[] args) throws Exception
{
ServerSocket ss = new ServerSocket(8888);
while(running)
{
Socket s = ss.accept();
process(s);
s.close();
}
ss.close();
}
private static void process(Socket s) throws Exception
{
InputStream in = s.getInputStream();
OutputStream out = s.getOutputStream();
DataInputStream dis = new DataInputStream(in);
DataOutputStream dos = new DataOutputStream(out);
ObjectInputStream ois = new ObjectInputStream(in);
ObjectOutputStream oos = new ObjectOutputStream(out);
String methodName = ois.readUTF();//读入方法名
Class[] parameterTypes = (Class[]) ois.readObject();//读入方法参数类型
Object[] args = (Object[]) ois.readObject();//读入方法参数
IUSerService serService = new USerServiceImpl();
Method method = serService.getClass().getMethod(methodName,parameterTypes);//调用方法
User user = (User)method.invoke(serService,args);
oos.writeObject(user);
dos.flush();
}
}
-----------------------------------------------------------------------------------------------------
package com.demo.rpc05;
import com.demo.IUSerService;
import com.demo.User;
import java.io.DataInputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.net.Socket;
public class Stub {
public static IUSerService getStub(){
InvocationHandler h = new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Socket s = new Socket("127.0.0.1",8888);
ObjectOutputStream oos = new ObjectOutputStream(s.getOutputStream());
ObjectInputStream ois = new ObjectInputStream(s.getInputStream());
String methodName = method.getName();
Class[] parameterTypes = method.getParameterTypes();//获取参数类型数组,这是防止重载带来的错误
oos.writeUTF(methodName);
oos.writeObject(parameterTypes);
oos.writeObject(args);//方法参数
oos.flush();
User user = (User)ois.readObject();
oos.close();
ois.close();
s.close();
return user;
}
};
Object o = Proxy.newProxyInstance(IUSerService.class.getClassLoader(),new Class[]{IUSerService.class},h);//生成代理类
return (IUSerService) o;
}
}
- ⑥第六个版本
特点:客户端传入所需业务的接口,服务端从注册表内找到相关类,再根据传入的方法调用业务
package com.demo.rpc06;
import com.demo.IUSerService;
public class Client {
public static void main(String[] args) throws Exception
{
IUSerService serService = (IUSerService) Stub.getStub(IUSerService.class);
System.out.println(serService.getUSerById(123));
}
}
---------------------------------------------------------------------------------------------------
package com.demo.rpc06;
import com.demo.IUSerService;
import com.demo.User;
import com.demo.rpc01.USerServiceImpl;
import java.io.*;
import java.lang.reflect.Method;
import java.net.ServerSocket;
import java.net.Socket;
public class Server {
private static boolean running = true;
public static void main(String[] args) throws Exception
{
ServerSocket ss = new ServerSocket(8888);
while(running)
{
Socket s = ss.accept();
process(s);
s.close();
}
ss.close();
}
private static void process(Socket s) throws Exception
{
InputStream in = s.getInputStream();
OutputStream out = s.getOutputStream();
DataInputStream dis = new DataInputStream(in);
DataOutputStream dos = new DataOutputStream(out);
ObjectInputStream ois = new ObjectInputStream(in);
ObjectOutputStream oos = new ObjectOutputStream(out);
String className = ois.readUTF();//读入类名
String methodName = ois.readUTF();//读入方法名
Class[] parameterTypes = (Class[]) ois.readObject();//读入方法参数类型
Object[] args = (Object[]) ois.readObject();//读入方法参数
Class clazz = null;
//从服务注册表找到具体类
clazz = USerServiceImpl.class;
Method method = clazz.getMethod(methodName,parameterTypes);//调用方法
User user = (User)method.invoke(clazz.getDeclaredConstructor().newInstance(),args);
oos.writeObject(user);
dos.flush();
}
}
----------------------------------------------------------------------------------------------------
package com.demo.rpc06;
import com.demo.HessionUtils.HessianUtils;
import com.demo.IUSerService;
import com.demo.User;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.net.Socket;
public class Stub {
public static Object getStub(Class clazz){
InvocationHandler h = new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Socket s = new Socket("127.0.0.1",8888);
ObjectOutputStream oos = new ObjectOutputStream(s.getOutputStream());
ObjectInputStream ois = new ObjectInputStream(s.getInputStream());
String clazzName = clazz.getName();
String methodName = method.getName();
Class[] parameterTypes = method.getParameterTypes();//获取参数类型数组,这是防止重载带来的错误
oos.writeUTF(clazzName);
oos.writeUTF(methodName);
oos.writeObject(parameterTypes);
oos.writeObject(args);//方法参数
oos.flush();
Object o = HessianUtils.deserialize(ois.readAllBytes());
oos.close();
ois.close();
s.close();
return o;
}
};
Object o = Proxy.newProxyInstance(clazz.getClassLoader(),new Class[]{clazz},h);//生成代理类
return o;
}
}
- ⑦第七个版本
特点:把Stub的getStub的返回值换成了Object,这样,传入不同的接口,就能调用不同的业务了
package com.demo.rpc07;
import com.demo.IProductService;
import com.demo.IUSerService;
import com.demo.rpc06.Stub;
public class Client {
public static void main(String[] args) throws Exception
{
IProductService serService = (IProductService) Stub.getStub(IProductService.class);
System.out.println(serService.getProById(123));
}
}
-------------------------------------------------------------------------------------
package com.demo.rpc07;
import com.demo.Product;
import com.demo.User;
import com.demo.rpc01.USerServiceImpl;
import java.io.*;
import java.lang.reflect.Method;
import java.net.ServerSocket;
import java.net.Socket;
public class Server {
private static boolean running = true;
public static void main(String[] args) throws Exception
{
ServerSocket ss = new ServerSocket(8888);
while(running)
{
Socket s = ss.accept();
process(s);
s.close();
}
ss.close();
}
private static void process(Socket s) throws Exception
{
InputStream in = s.getInputStream();
OutputStream out = s.getOutputStream();
DataInputStream dis = new DataInputStream(in);
DataOutputStream dos = new DataOutputStream(out);
ObjectInputStream ois = new ObjectInputStream(in);
ObjectOutputStream oos = new ObjectOutputStream(out);
String className = ois.readUTF();//读入类名
String methodName = ois.readUTF();//读入方法名
Class[] parameterTypes = (Class[]) ois.readObject();//读入方法参数类型
Object[] args = (Object[]) ois.readObject();//读入方法参数
Class clazz = null;
//从服务注册表找到具体类
clazz = ProductServiceImpl.class;
Method method = clazz.getMethod(methodName,parameterTypes);//调用方法
Product product = (Product)method.invoke(clazz.getDeclaredConstructor().newInstance(),args);
oos.writeObject(product);
dos.flush();
}
}
---------------------------------------------------------------------------------------------------------
package com.demo.rpc07;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.net.Socket;
public class Stub {
public static Object getStub(Class clazz){
InvocationHandler h = new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Socket s = new Socket("127.0.0.1",8888);
ObjectOutputStream oos = new ObjectOutputStream(s.getOutputStream());
ObjectInputStream ois = new ObjectInputStream(s.getInputStream());
String clazzName = clazz.getName();
String methodName = method.getName();
Class[] parameterTypes = method.getParameterTypes();//获取参数类型数组,这是防止重载带来的错误
oos.writeUTF(clazzName);
oos.writeUTF(methodName);
oos.writeObject(parameterTypes);
oos.writeObject(args);//方法参数
oos.flush();
Object o = ois.readObject();
oos.close();
ois.close();
s.close();
return o;
}
};
Object o = Proxy.newProxyInstance(clazz.getClassLoader(),new Class[]{clazz},h);//生成代理类
return o;
}
}
- ⑧第八个版本
特点:Hessian的简单用法
package com.demo.rpc08_Hessian01;
import com.caucho.hessian.io.Hessian2Input;
import com.caucho.hessian.io.Hessian2Output;
import com.demo.User;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.util.HashMap;
public class HelloHessian {
public static void main(String[] args) throws Exception
{
User user = new User("zhangsan",1);
System.out.println("hession:"+serialize(user).length);
}
public static byte[] serialize(Object o) throws Exception
{
ByteArrayOutputStream baos = new ByteArrayOutputStream();
Hessian2Output output = new Hessian2Output(baos);
output.writeObject(o);
output.flush();
byte[] bytes = baos.toByteArray();
baos.close();
output.close();
return bytes;
}
public static Object deserialize(byte[] bytes) throws Exception
{
ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
Hessian2Input input = new Hessian2Input(bais);
Object o = input.readObject();
bais.close();
input.close();
return o;
}
}
- ⑨第九个版本
特点:对比JDK序列化和Hessian序列化
package com.demo.rpc09_Hessian02;
import com.caucho.hessian.io.Hessian2Output;
import com.demo.User;
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.ObjectOutputStream;
public class HessianVsJdk {
public static void main(String[] args) throws Exception
{
User user = new User("zhangsan",1);
System.out.println("Hessian:"+hessianSerial(user).length);
System.out.println("JDK:"+jdkSerial(user).length);
}
public static byte[] hessianSerial(Object o) throws Exception
{
ByteArrayOutputStream out = new ByteArrayOutputStream();
Hessian2Output output = new Hessian2Output(out);
output.writeObject(o);
output.flush();
byte[] bytes = out.toByteArray();
out.close();
output.close();
return bytes;
}
public static byte[] jdkSerial(Object o) throws Exception
{
ByteArrayOutputStream out = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(out);
oos.writeObject(o);
oos.flush();
byte[] bytes = out.toByteArray();
out.close();
oos.close();
return bytes;
}
}