手写RPC框架(二)加入动态代理

手写RPC框架(二)加入动态代理

如果没有动态代理,远程调用时,需要对每个类都要建立代理,这样会导致代码十分冗余,我们通过Java中Proxy,动态的构建类,来实现AOP的功能。

public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces, InvocationHandler h)

通过此方法,我们通过传入类加载器,接口信息以及InvocationHandler就可以为Consumer创建代理类

对于InvocationHandler,相当于AOP中的拦截器,所有调用代理类的方法都会被拦截下来转到InvocationHandler中的invoke中执行。因此,我们在Consumer实现时,需要在invoke方法中,将类的调用信息(类名,方法名、参数等)序列化后打包,通过socket发送给Provider来执行远程过程调用。

  • 数据包类的实现,因为需要通过反射的方式执行方法,因此我们需要将函数的全部执行信息都要进行序列化,定义一个请求包类如下:

    package request;
    
    import java.io.Serializable;
    
    public class RpcRequest implements Serializable {
    
        private static final long serialVersionUID = 6011503509272346423L;
        //类名
        public String className;
        //方法名
        private String methodName;
        //参数类型
        private Class<?>[] parameterTypes;
        //参数
        private Object[] arguments;
    
        public String getClassName() {
            return className;
        }
    
        public void setClassName(String className) {
            this.className = className;
        }
    
        public String getMethodName() {
            return methodName;
        }
    
        public void setMethodName(String methodName) {
            this.methodName = methodName;
        }
    
        public Class<?>[] getParameterTypes() {
            return parameterTypes;
        }
    
        public void setParameterTypes(Class<?>[] parameterTypes) {
            this.parameterTypes = parameterTypes;
        }
    
        public Object[] getArguments() {
            return arguments;
        }
    
        public void setArguments(Object[] arguments) {
            this.arguments = arguments;
        }
    
        public RpcRequest() {
        }
    
        public RpcRequest(String className, String methodName, Class<?>[] parameterTypes, Object[] arguments) {
            this.className = className;
            this.methodName = methodName;
            this.parameterTypes = parameterTypes;
            this.arguments = arguments;
        }
    }
    
  • Consumer的实现,相当于AOP的拦截器,需要实现InvocationHandler接口,实现逻辑卸载invoke方法中

    public class ConsumerProxy implements InvocationHandler {
    	//被代理类
        private final Class<?> serviceClass;
    
        public ConsumerProxy(Class<?> serviceClass) {
            this.serviceClass = serviceClass;
        }
    
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            Socket socket = new Socket("127.0.0.1", 8889);
            ObjectOutputStream objectOutputStream = new ObjectOutputStream(socket.getOutputStream());
            //数据打包
            RpcRequest rpcRequest = new RpcRequest(serviceClass.getName(), method.getName(), method.getParameterTypes(), args);
            //通过socket发送数据
            objectOutputStream.writeObject(rpcRequest);
            //接收返回数据
            ObjectInputStream inputStream = new ObjectInputStream(socket.getInputStream());
            return inputStream.readObject();
        }
    
  • Provider的实现,从socket中解析数据并执行方法

    public class Provider {
        public static void main(String[] args) throws IOException {
            ServerSocket serverSocket = new ServerSocket(8889);
            try{
                Socket accept = serverSocket.accept();
                ObjectInputStream objectInputStream = new ObjectInputStream(accept.getInputStream());
                RpcRequest rpcRequest=(RpcRequest)objectInputStream.readObject();
                // 读取类名
                String classFullName=rpcRequest.getClassName();
                // 读取方法名
                String methodName=rpcRequest.getMethodName();
                // 读取方法入参类型
                Class<?>[] parameterTypes=rpcRequest.getParameterTypes();
                // 读取方法调用入参
                Object[] parameters=rpcRequest.getArguments();
                Class<?> aClass = Class.forName(classFullName);
                Method method = aClass.getMethod(methodName, parameterTypes);
                //通过反射执行方法
                Object invoke = method.invoke(aClass.newInstance(), parameters);
                ObjectOutputStream objectOutputStream = new ObjectOutputStream(accept.getOutputStream());
                objectOutputStream.writeObject(invoke);
            } catch (ClassNotFoundException | NoSuchMethodException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (InstantiationException e) {
                e.printStackTrace();
            }
        }
    }
    
  • 通过动态代理发起RPC请求

    public class ConsumerApp {
    
        public static void main(String[] args) {
            //创建代理类的InvocationHandler
            ConsumerProxy proxy=new ConsumerProxy(CalculatorImpl.class);
            //创建代理类
            //代理类会声明被代理类的接口
            Calculator cal=(Calculator) Proxy.newProxyInstance(Calculator.class.getClassLoader(),new Class<?>[]{Calculator.class},proxy);
            //调用
            int a=cal.div(5,1);
            System.out.println("RPC CONNECTED!"+a);
        }
    }
    

通过动态代理,我们可以很容易在代码执行阶段构建出代理对象,实现一些日志记录,时间统计等功能,同样在RPC框架中,动态代理使得我们不需要为每个类都创建一个代理类,让RPC框架更加通用化。

Java动态代理

代码地址 (v2.0)

上一篇:分布式与微服务的关系


下一篇:实现整数转化为字符串函数itoa()函数