脚本宝典收集整理的这篇文章主要介绍了手写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)
以上是脚本宝典为你收集整理的手写RPC框架(二)加入动态代理全部内容,希望文章能够帮你解决手写RPC框架(二)加入动态代理所遇到的问题。
本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
如您有任何意见或建议可联系处理。小编QQ:384754419,请注明来意。