文档章节

源码模仿之RPC

GMarshal
 GMarshal
发布于 09/26 22:21
字数 959
阅读 6
收藏 0

源码模仿之RPC

RPC - 远程过程调用,概念不多赘述,可自行百度。

场景

  • 统一api接口
  • 生产者(提供远程接口调用方)
  • 使用者(主动调用远程接口)

代码实现

API接口(公共依赖包)

DemoEntity (实体类)

/**
 * 测试对象
 * @author GaoYuan
 */
public class DemoEntity implements Serializable{

    private String id;
    private String name;

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

公共接口(需要预先约定好)

public interface IDemoService {
    DemoEntity getDemo(String id);
}

远程调用提供者

DemoService (需要接口的具体实现)

/**
 * 接口具体实现
 * @author GaoYuan
 */
public class DemoService implements IDemoService {

    @Override
    public DemoEntity getDemo(String id) {
        DemoEntity demoEntity = new DemoEntity();
        demoEntity.setId("1");
        demoEntity.setName("gaoyuan");
        return demoEntity;
    }
}

ProviderStarter (提供者启动类)

/**
 * 接口提供者
 * @author GaoYuan
 */
public class ProviderStarter {

    public static void main(String[] args){
        try {
            // 搭建 8080 端口的socket监听服务
            ServerSocket serverSocket = new ServerSocket(8989);
            while (true){
                Socket socket = serverSocket.accept();
                // 获取socket的输入流(即其他服务进行请求的参数,主要是获取调用的类名、方法名、参数等)
                ObjectInputStream objectInputStream = new ObjectInputStream(socket.getInputStream());

                String className = objectInputStream.readUTF();
                System.out.println(">>>>>> [接收]:" + className);
                String methodName = objectInputStream.readUTF();
                System.out.println(">>>>>> [接收]:" + methodName);
                Class[] methodParameterTypes = (Class[]) objectInputStream.readObject();
                System.out.println(">>>>>> [接收]:" + methodParameterTypes);
                Object[] methodArgs = (Object[]) objectInputStream.readObject();
                System.out.println(">>>>>> [接收]:" + methodArgs);

                Class myclass = null;

                // 这里主要是解决如何通过接收到的类名为"IDemoService" 转换为 具体的实现"DemoService"
                if(IDemoService.class.getName().equals(className)){
                    // 此时 myclass已经是具体的实现类了
                    myclass = ClassLoader.getSystemClassLoader().loadClass("com.foruo.simple.rpc.provider.DemoService");
                    // myclass = DemoService.class; // 也可以用这种方式获取class
                    System.out.println(">>>>>> [组装]:指定实现类DemoService");
                }

                // 获取具体实现类的方法
                Method method = myclass.getMethod(methodName, methodParameterTypes);
                System.out.println(">>>>>> [组装]:指定方法");
                // 获取实现类方法执行的结果
                Object invoke = method.invoke(myclass.newInstance(), methodArgs);
                System.out.println(">>>>>> [执行]:指定实现类的指定方法");
                System.out.println(">>>>>> [执行]:获取方法执行结果");
                System.out.println(">>>>>> [回执]:将执行结果输出");
                // 将执行结果输出
                ObjectOutputStream objectOutputStream = new ObjectOutputStream(socket.getOutputStream());
                objectOutputStream.writeObject(invoke);
                objectOutputStream.flush();

                // 关闭流
                objectInputStream.close();
                objectOutputStream.close();
                // 关闭socket
                socket.close();
            }
        }catch (Exception e){
            e.printStackTrace();
        }
    }
}

消费者(使用方)

ConsumerStarter

/**
 * 消费者 - 使用远程接口
 * @author GaoYuan
 */
public class ConsumerStarter {

    public static void main(String[] args){
        // 这里实际上相当于获取了IDemoService的实现
        IDemoService demoService = (IDemoService)simpleRpc(IDemoService.class);
        // 执行getDemo方法时,相当于调用了代理的处理方法
        DemoEntity demoEntity = demoService.getDemo("1");
        System.out.println(demoEntity.getName());
    }

    /**
     * 远程调用具体代码
     * @author GaoYuan
     */
    public static Object simpleRpc(Class myClass){
        return Proxy.newProxyInstance(myClass.getClassLoader(), new Class[]{myClass}, (proxy, method, args) -> {
            // socket连接8080端口
            Socket socket = new Socket("127.0.0.1", 8989);

            // 获取类名 (这里是获取 IDemoService 接口名)
            String className = myClass.getName();
            // 获取方法名
            String methodName = method.getName();
            // 获取方法参数
            Class[] methodParameterTypes = method.getParameterTypes();

            /**
             * 这里主要将 需要调用的目标方法(包含对象类名/接口名)以socket形式传递过去,以调用远程接口
             * 就是告诉远程接口,我想要调用什么方法
             * */
            ObjectOutputStream objectOutputStream = new ObjectOutputStream(socket.getOutputStream());
            objectOutputStream.writeUTF(className);
            System.out.println(">>>>>> [发送]:" + className);
            objectOutputStream.writeUTF(methodName);
            System.out.println(">>>>>> [发送]:" + methodName);
            objectOutputStream.writeObject(methodParameterTypes);
            System.out.println(">>>>>> [发送]:" + methodParameterTypes);
            objectOutputStream.writeObject(args);
            System.out.println(">>>>>> [发送]:" + args);
            objectOutputStream.flush();

            /** 获取远程接口执行结果 */
            ObjectInputStream objectInputStream = new ObjectInputStream(socket.getInputStream());
            Object o = objectInputStream.readObject();
            System.out.println(">>>>>> [接收]:" + o);
            // 关闭流
            objectInputStream.close();
            objectOutputStream.close();
            // 关闭socket
            socket.close();

            return o;
        });
    }
}

执行

先启动 ProviderStarter ,再启动 ConsumerStarter

输出

ProviderStarter

>>>>>> [接收]:com.foruo.simple.rpc.service.IDemoService
>>>>>> [接收]:getDemo
>>>>>> [接收]:[Ljava.lang.Class;@3c5a99da
>>>>>> [接收]:[Ljava.lang.Object;@47f37ef1
>>>>>> [组装]:指定实现类DemoService
>>>>>> [组装]:指定方法
>>>>>> [执行]:指定实现类的指定方法
>>>>>> [执行]:获取方法执行结果
>>>>>> [回执]:将执行结果输出

ConsumerStarter

>>>>>> [发送]:com.foruo.simple.rpc.service.IDemoService
>>>>>> [发送]:getDemo
>>>>>> [发送]:[Ljava.lang.Class;@6a5fc7f7
>>>>>> [发送]:[Ljava.lang.Object;@6fadae5d
>>>>>> [接收]:com.foruo.simple.rpc.entity.DemoEntity@7a5d012c
gaoyuan

可见,最终消费者获取到了远程调用的返回值。

博客

开源中国博客地址

https://my.oschina.net/gmarshal

个人博客地址

http://blog.foruo.top

欢迎关注我的个人微信订阅号:(据说这个头像程序猿专用)

输入图片说明

© 著作权归作者所有

共有 人打赏支持
GMarshal
粉丝 15
博文 47
码字总数 37825
作品 0
南京
程序员
PHP 版本的服务调用框架--PHP_Soa_FrameWork

在实际工作中发现没有类似Dubbo那种成熟度比较高的PHP服务框架,去年正好工作不是特别忙,就模仿Dubbo写了一个服务框架。 使用Zookeeper提供服务注册和服务发现功能,通过TCP+JSON的方式进行...

Kevin6188
2016/08/02
821
1
Hadoop中RPC机制详解之Client端

先看看这个吧, Hadoop 中 RPC 机制简介, Hadoop 中 RPC 机制的实现都在 org.apache.hadoop.ipc 这个包里, 下面都将围绕这个包解读 Hadoop RPC 机制 1. RPC.getServer(Object instance, Stri...

wall--e
2016/05/05
236
0
spark2.1.0之源码分析——RPC客户端TransportClient详解

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/beliefer/article/details/82143001 提示:阅读本文前最好先阅读: 《Spark2.1.0之内置RPC框架》 《spark2.1....

泰山不老生
08/28
0
0
模仿酷狗7(Kugou7)音乐魔方界面源码

源码名称:模仿酷狗7(Kugou7)界面源码 源码作者:邓学彬(泪闯天涯) 源码说明:内含VC++源码、易语言源码各一份.包含所有图片源码(使用Fireworks编辑) 开发环境:VC版--VS2005、Gdiplus;易语...

邓学彬
2012/12/09
0
0
spark2.1.0之源码分析——RPC管道初始化

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/beliefer/article/details/81197447 提示:阅读本文前最好先阅读: 《Spark2.1.0之内置RPC框架》 《spark2.1....

泰山不老生
07/25
0
0

没有更多内容

加载失败,请刷新页面

加载更多

线性一致性和 Raft

作者:沈泰宁 在讨论分布式系统时,共识算法(Consensus algorithm)和一致性(Consistency)通常是讨论热点,两者的联系很微妙,很容易搞混。一些常见的误解:使用了 Raft [0] 或者 paxos ...

TiDB
20分钟前
0
0
兄弟连区块链教程以太坊源码分析core-state-process源码分析

## StateTransition状态转换模型 /* The State Transitioning Model 状态转换模型 A state transition is a change made when a transaction is applied to the cu......

兄弟连区块链入门教程
22分钟前
0
0
linear-gradient渐变中的参数

在看张鑫旭的博客 遇到渐变数值后面带参数不太理解 @supports (-webkit-mask: none) or (mask: none) { .box { border: none; background: linear-gradient(to bottom, #34538...

红羊在厦门
23分钟前
0
0
Python yagmail模块自动发邮件

Python发邮件yagmail模块 import yagmail#连接服务器yag=yagmail.SMTP('xx@163.com','yy','smtp.163.com')#邮箱正文contents=["test","email send"]#发送邮件#yag.send('...

小白兔_球球
24分钟前
1
0
pada mysql

CREATE SCHEMA `exchange` DEFAULT CHARACTER SET utf8mb4 ;

qwfys
33分钟前
2
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部