手写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框架更加通用化。
代码地址 (v2.0)