手写 RPC(一)基于 BIO,深入理解远程调用原理

                                                                              【诗119:130】你的言语一解开,就发出亮光,使愚人通达。


目录

rpc-server-all(服务端实现)

        rpc-server-api

        rpc-server-provider

rpc-client(客户端实现)

完成 -> 测试

源码


 

  • 创建两个项目

服务端:rpc-server-all

客户端:rpc-client

 

  • rpc-server-all(服务端实现)


服务端创建两个模块

  • rpc-server-api:供客户端使用的 API
  • rpc-server-provider: api 的具体实现以及 bio 服务器的实现
  • rpc-server-api

IHelloSevice(对外发布的接口)

public interface IHelloSevice {
    String sayHello(String name);
    void saveUser(User user);
}

RpcRequest(请求体),自己生成 get和set

package com.ddup.rpc;
import java.io.Serializable;
/**
 * 请求体
 */
public class RpcRequest implements Serializable {
    public String className;//类名
    public String methodName;//方法名
    public Object[] parameters;//请求实参
}

User (业务entity,get和set忽略,自己生成)

public class User implements Serializable {
    private String name;
    private int age;
}

最后:maven -> install(把此模块打成 jar 到本地仓库,对外提供调用)

  • rpc-server-provider

pom.xml 引入 rpc-server-api

        <dependency>
            <groupId>com.ddup.rpc</groupId>
            <artifactId>rpc-server-api</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>

 业务实现

public class HelloServerImpl implements IHelloSevice {

    @Override
    public String sayHello(String name) {
        System.out.println("reqeust in content : " + name);
        return "hello " + name;
    }

    @Override
    public void saveUser(User user) {
        System.out.println("request in saveUser : "+ user.toString());

    }

服务端:RpcProxyServer

package com.ddup.rpc;
/**
 * 服务端:阻塞接收请求
 */
public class RpcProxyServer {
    /**
     * 缓存线程池
     */
    private ExecutorService executorService = Executors.newCachedThreadPool();

    public void publish(int port, Object service) {
        ServerSocket serverSocket = null;
        try {
            serverSocket = new ServerSocket(port);
            while (true) {
                Socket socket = serverSocket.accept();
                // 利用多线程处理任务
                executorService.execute(new ProcessorHandler(socket, service));
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (serverSocket != null) {
                try {
                    serverSocket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

请求处理类:ProcessorHandler

package com.ddup.rpc;
/**
 * 用以处理请求,反射实现
 */
public class ProcessorHandler implements Runnable {
    private Socket socket;
    private Object service;

    public ProcessorHandler(Socket socket, Object service) {
        this.socket = socket;
        this.service = service;
    }

    @Override
    public void run() {
        try {
            ObjectInputStream ois = new ObjectInputStream(socket.getInputStream());
            RpcRequest request = (RpcRequest) ois.readObject();
            Object result = invoke(request);
            ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());
            // 结果返回给客户端
            oos.writeObject(result);
            oos.flush();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }finally {
            if (socket != null) {
                try {
                    socket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    public Object invoke(RpcRequest request) {
        Object result = null;
        try {
            // 获取形参类型
            Object[] parameters = request.getParameters();
            Class<?>[] parameterTypes = new Class[parameters.length];
            for (int i = 0; i < parameters.length; i++) {
                parameterTypes[i] = parameters[i].getClass();
            }
            String className = request.getClassName();
            Class<?> clzz = Class.forName(className);
            String methodName = request.getMethodName();
            // 找到方法
            Method method = clzz.getMethod(methodName, parameterTypes);
            //反射调用
            result = method.invoke(service, parameters);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
        return result;
    }
}

启动

package com.ddup.rpc;

/**
 * Hello world!
 */
public class App {
    public static void main(String[] args) {
        
        HelloServerImpl helloServer = new HelloServerImpl();
        RpcProxyServer rpcProxyServer = new RpcProxyServer();
        rpcProxyServer.publish(8080,helloServer);
    }
}

服务端结构

服务端完成.......

  • rpc-client(客户端实现)


RpcProxyClient)

package com.ddup.rpc;
import java.lang.reflect.Proxy;
/**
 * 客户端:用以生成所要调用接口的代理类
 */
public class RpcProxyClient {

    public <T> T clientProxy(final Class<T> interfaceCls,String host,int port) {
            return (T)Proxy.newProxyInstance(interfaceCls.getClassLoader(), new Class<?>[]{interfaceCls}, new RemoteInvocationHandler(host,port));
    }
}

RemoteInvocationHandler 

实现 InvocationHandler 接口,用以生成代理类,持有代理方法 #invoke

package com.ddup.rpc;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
/**
 * 执行真正方法的类,实现 InvocationHandler 接口
 */
public class RemoteInvocationHandler implements InvocationHandler {
    private String host;
    private int port;

    public RemoteInvocationHandler(String host, int port) {
        this.host = host;
        this.port = port;
    }

    /**
     * 代理方法 
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("client come in invoking...");
        // 请求体
        RpcRequest request = new RpcRequest();
        request.setClassName(method.getDeclaringClass().getName());
        request.setMethodName(method.getName());
        request.setParameters(args);
        // 发起网络传输
        RpcNetTransport rpcNetTransport = new RpcNetTransport(host, port);
        Object result = rpcNetTransport.send(request);
        return result;
    }
}

RpcNetTransport 

用以发起真正的网络传输,处理请求和响应

package com.ddup.rpc;
import java.io.*;
import java.net.Socket;
/**
 * 发起网络传输的类
 */
public class RpcNetTransport {
    private String host;
    private int port;

    public RpcNetTransport(String host, int port) {
        this.host = host;
        this.port = port;
    }

    public Object send(RpcRequest request) {
        Object result = null;
        ObjectOutputStream oos = null;
        ObjectInputStream ois = null;
        try {
            Socket socket = null;
            try {
                socket = new Socket(host, port);
            } catch (IOException e) {
                e.printStackTrace();
            }
            OutputStream os = socket.getOutputStream();
            oos = new ObjectOutputStream(os);
            oos.writeObject(request);
            oos.flush();
            InputStream is = socket.getInputStream();
            ois = new ObjectInputStream(is);
            result = ois.readObject();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } finally {
            if (ois != null) {
                try {
                    ois.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (oos != null) {
                try {
                    oos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return result;
    }
}

启动

package com.ddup.rpc;
/**
 * Hello world!
 */
public class App {
    public static void main(String[] args) {
        RpcProxyClient rpcProxyClient = new RpcProxyClient();
        IHelloSevice iHelloSevice = rpcProxyClient.clientProxy(IHelloSevice.class,"localhost",8080);
        String zqr = iHelloSevice.sayHello("zqr");
        System.out.println(zqr);
    }
}

客户端结构

  • 完成 -> 测试


#main启动服务端 -> #main 启动客户端 —> 成功

服务端打印

客户端打印

  • 源码

服务端  git@github.com:qingruizhu/rpc-server-all.git

客户端  git@github.com:qingruizhu/rpc-client.git

                                                                                                        左手圣经,右手Java

                                                                                                灵魂指导思想,思想更新技术

                                                                                        一个对圣经感兴趣的Java菜鸟 ? -> 留言指导哦?亲

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值