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;
    }
}



















