RPC学习笔记

news2024/11/24 6:16:26

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具体步骤?

  1. 服务消费者(client客户端)通过本地调用的方式调用服务。
  2. 客户端存根(client stub)接收到请求后负责将方法、入参等信息序列化(组装)成能够进行网络传输的消息
    体。
  3. 客户端存根(client stub)找到远程的服务地址,并且将消息通过网络发送给服务端。
  4. 服务端存根(server stub)收到消息后进行解码(反序列化操作)。
  5. 服务端存根(server stub)根据解码结果调用本地的服务进行相关处理。
  6. 本地服务执行具体业务逻辑并将处理结果返回给服务端存根(server stub)。
  7. 服务端存根(server stub)将返回结果重新打包成消息(序列化)并通过网络发送至消费方。
  8. 客户端存根(client stub)接收到消息,并进行解码(反序列化)。
  9. 服务消费方得到最终结果。
    RPC

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对对象进行序列化和反序列化。
  • 缺点:
  1. 只能支持Java语言,不能跨语言使用。
  2. 不好用,语法生硬
  3. 速度慢,序列化的字节数组长度比较长,所占空间大

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


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/761542.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

CodeArts Check系统规则集还不够?带你体验如何创建、启用自定义规则集

代码检查(CodeArts Check)是基于云端实现的代码检查服务。建立在多年自动化源代码静态检查技术积累与企业级应用经验的沉淀之上,为用户提供代码风格、通用质量与网络安全风险等丰富的检查能力,提供全面质量报告、便捷闭环处理问题…

BTY生态系统DNS关于DeSoc的构想

2022年5月,以太坊创始人Vitalik Buterin与经济学家Glen Weyl和Flashbots研究员Puja Ohlhaver联合发布了《Decentralized Society: Finding Web3’s Soul》。这篇论文的核心是围绕“Web3灵魂”创造出去中心化社会的可能性。 论文中阐述,当下Web3 更多是表…

Java语言基础

目录 一.代码注释 二.变量与常量 1.标识符 2.关键字 3.变量 4.常量 三.基本数据类型 1.整数类型 2.浮点类型 3.字符类型 1.char型 2.转义字符 4.布尔类型 一.代码注释 在代码中添加注释能提高代码的可读性。注释中包含了程序的信息,可以帮助程序员更…

前端学习——JS进阶 (Day3)

编程思想 面向过程编程 面向对象编程 (oop) 构造函数 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta http-equiv"X-UA-Compatible" content"IEedge"><meta name"viewport…

第一阶段-第十章 Python基础的综合案例(数据可视化-折线图可视化)

目录 一、本章的案例介绍  1.可视化案例&#xff08;本章&#xff09;的学习目标  2.需要实现的效果图  3.数据来源 二、json数据格式  1.学习目标  2.什么是json  3. json的作用  4.json的语法要求  5.Python数据和json数据的相互转化&#xff08;dumps转json…

卷积神经网络识别人脸项目—使用百度飞桨ai计算

卷积神经网络识别人脸项目的详细过程 整个项目需要的准备文件&#xff1a; 下载链接&#xff1a; 链接&#xff1a;https://pan.baidu.com/s/1WEndfi14EhVh-8Vvt62I_w 提取码&#xff1a;7777 链接&#xff1a;https://pan.baidu.com/s/10weqx3r_zbS5gNEq-xGrzg 提取码&#x…

❤️创意网页:打造简洁美观的网页轮播图(HTML简单实现轮播图)操作简单可以直接使用

✨博主&#xff1a;命运之光 &#x1f338;专栏&#xff1a;Python星辰秘典 &#x1f433;专栏&#xff1a;web开发&#xff08;简单好用又好看&#xff09; ❤️专栏&#xff1a;Java经典程序设计 ☀️博主的其他文章&#xff1a;点击进入博主的主页 前言&#xff1a;欢迎踏入…

MQTT协议在物联网环境中的应用及代码实现解析(一)

MQTT协议全称是Message Queuing Telemetry Transport&#xff0c;翻译过来就是消息队列遥测传输协议&#xff0c;它是物联网常用的应用层协议&#xff0c;运行在TCP/IP中的应用层中&#xff0c;依赖TCP协议&#xff0c;因此它具有非常高的可靠性&#xff0c;同时它是基于TCP协议…

macos使用搭建算法竞赛c/c++的g++/gcc编译环境(homebrew,含万能头,改环境变量,vscode/clion可用)

文章目录 1、homebrew安装2、安装g3、改环境变量 1、homebrew安装 我没改镜像&#xff0c;直接网上脚本一键安装的&#xff0c;具体命令忘了&#xff0c;可能是这个 反正装这个的方法很多&#xff0c;网上一搜都有。 成功装上homebrew就行。 /bin/bash -c "$(curl -fsSL…

一款功能强大的子域收集工具OneForAll

简介 借助官方的宣传简介阐述一下&#xff1a; 在渗透测试中信息收集的重要性不言而喻&#xff0c;子域收集是信息收集中必不可少且非常重要的一环&#xff0c;目前网上也开源了许多子域收集的工具&#xff0c;但是总是存在以下部分问题&#xff1a; 不够强大&#xff0c;子域…

基于Cyclone V SoC利用HLS实现卷积手写体数字识别设计

基于Cyclone V SoC利用HLS实现卷积手写体数字识别设计 本文是基于英特尔 Cyclone V SoC 开发板&#xff0c;利用 HLS 技术实现三层卷积两层池化两层全连接推理运算的手写体数字识别设计 硬件环境&#xff1a; Cyclone V SoC开发板 SD卡 电脑 软件环境&#xff1a; Windows 11 Q…

unity3d:YooAsset shader变体收集代码解析

开始收集 YooAsset.Editor.ShaderVariantCollector.Run 创建临时场景 // 创建临时测试场景CreateTempScene();_steps ESteps.Prepare;EditorApplication.update EditorUpdate;准备阶段 反射调用ShaderUtil.ClearCurrentShaderVariantCollection清空当前项目搜集到的变体&…

第52步 深度学习图像识别:Transformer in Transformer建模(Pytorch)

基于WIN10的64位系统演示 一、写在前面 &#xff08;1&#xff09;Transformer in Transformer Transformer in Transformer&#xff08;TNT&#xff09;模型是一种新的图像分类模型&#xff0c;由研究者在2021年提出。这种模型的特点是在传统的Vision Transformer模型的基础…

FreeRTOS源码分析-1创建任务

目录 1 任务的句柄&#xff08;结构体&#xff09; 2 创建任务主要工作 2.1 创建任务初始化源码分析 2.2 任务添加到就绪列表源码分析 2.3任务堆栈的初始化源码分析 问&#xff1a;R0为什么要入栈保存&#xff1f;因为作为函数的第一个传入参数&#xff0c;必须也要保存。…

spring复习:(37)ProxyFactoryBean之getObject

该工厂bean的getObject代码如下&#xff1a; public Object getObject() throws BeansException {initializeAdvisorChain();if (isSingleton()) {return getSingletonInstance();}else {if (this.targetName null) {logger.info("Using non-singleton proxies with sing…

4.CSS图文样式

考点&#xff1a;line-height为200%时&#xff0c;font-size为40px

第十五章:DenseASPP for Semantic Segmentation in Street Scenes——在街景语义分割中的DenseASPP

0.摘要 语义图像分割是自动驾驶中的基本街景理解任务&#xff0c;在这个任务中&#xff0c;高分辨率图像中的每个像素被归类为一组语义标签。与其他场景不同&#xff0c;自动驾驶场景中的物体呈现出非常大的尺度变化&#xff0c;这给高级特征表示带来了巨大挑战&#xff0c;因为…

IDEA设置显示行号和方法间的分隔符

IDEA设置显示行号和方法间的分隔符 选择File--Settings--Edotor-General-Apperance&#xff0c;勾选上下图中的选项后点击 OK 即可。 每个函数不迷路~~ Show line numbers&#xff1a;显示行数 Show method separators&#xff1a; 显示方法分隔线。

央视赋能,强势出击——方圆出海与《品牌中国》栏目达成战略合作

2023 央视赋能&#xff0c;强势出击 方圆出海 “日前&#xff0c;深圳市方圆出海科技有限公司与《品牌中国》栏目携手&#xff0c;双方正式达成战略合作协议&#xff0c;央视《品牌中国》栏目负责人正式授予方圆出海“《品牌中国》重点推荐品牌”的荣誉称号。 此次签约标志着…

js的this绑定规则以及箭头函数

目录 调用位置默认绑定隐式绑定隐式丢失 显式绑定callapplybind new绑定装箱绑定优先级this规则之外忽略显式绑定间接函数引用 箭头函数 调用位置 从字面意思上来理解&#xff0c;this似乎是指向自己的 然而在JavaScript中&#xff0c;this并不是绑定到自身的 可以看这一个例子…