手撸RPC框架 动态代理屏蔽RPC服务调用底层细节
大家好,我是小趴菜,接下来我会从0到1手写一个RPC框架,该专题包括以下专题,有兴趣的小伙伴就跟着我一起学习吧
本章源码地址:gitee.com/baojh123/se…
自定义注解 -> opt-01 服务提供者收发消息基础实现 -> opt-01 自定义网络传输协议的实现 -> opt-02 自定义编解码实现 -> opt-03 服务提供者调用真实方法实现 -> opt-04 完善服务消费者发送消息基础功能 -> opt-05 注册中心基础功能实现 -> opt-06 服务提供者整合注册中心 -> opt-07 服务消费者整合注册中心 -> opt-08 完善服务消费者接收响应结果 -> opt-09 服务消费者,服务提供者整合SpringBoot -> opt-10 动态代理屏蔽RPC服务调用底层细节 -> opt-10 SPI机制基础功能实现 -> opt-11 SPI机制扩展随机负载均衡策略 -> opt-12 SPI机制扩展轮询负载均衡策略 -> opt-13 SPI机制扩展JDK序列化 -> opt-14 SPI机制扩展JSON序列化 -> opt-15 SPI机制扩展protustuff序列化 -> opt-16
前言
在上一章中,我们已经成功的将服务提供者和服务消费者与SpringBoot成功整合了。但是在那一章中,我们已经实现了基于动态代理来屏蔽了RPC顶层服务调用的细节,这一章来说明如何去实现动态代理
实现
新建 xpc-rpc-proxy 代理模块,然后在创建二个子模块
- com.xpc.proxy.common.ObjectProxy
package com.xpc.proxy.common; import com.xpc.proxy.common.consumer.Consumer; import com.xpc.rpc.common.enums.RpcMsgType; import com.xpc.rpc.protocol.ProtocolMessage; import com.xpc.rpc.protocol.header.RpcHeader; import com.xpc.rpc.protocol.request.RpcRequest; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; public class ObjectProxy implements InvocationHandler { private Consumer consumer; private Class clazz; public ObjectProxy(Consumer consumer,Class clazz) { this.consumer = consumer; this.clazz = clazz; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { //开始构造请求对象 ProtocolMessage rpcRequestProtocolMessage = new ProtocolMessage(); RpcRequest rpcRequest = new RpcRequest(); RpcHeader rpcHeader = new RpcHeader(); rpcHeader.setMsgType(RpcMsgType.REQUEST.getType()); rpcHeader.setRequestId(1L); rpcRequestProtocolMessage.setRpcHeader(rpcHeader); rpcRequest.setClassName(clazz.getName()); rpcRequest.setMethodName(method.getName()); rpcRequest.setParameterTypes(method.getParameterTypes()); rpcRequest.setParameters(args); rpcRequestProtocolMessage.setT(rpcRequest); //发送请求 return consumer.sendRequest(rpcRequestProtocolMessage); } }
- Consumer:客户端发送请求的接口,RpcConsumer是它的具体实现
- Class:代理接口的class,我们是给接口直接进行代理,所以这个Class也就是这个被代理的
接口的class
创建获取代理的通用接口:com.xpc.proxy.common.ProxyFactory
package com.xpc.proxy.common; import com.xpc.proxy.common.consumer.Consumer; public interface ProxyFactory { /** * 获取代理对象 */ T getProxy(Class clazz); }
JDK动态代理实现: com.xpc.rpc.proxy.jdk.JdkProxy
package com.xpc.rpc.proxy.jdk; import com.xpc.proxy.common.ObjectProxy; import com.xpc.proxy.common.ProxyFactory; import com.xpc.proxy.common.consumer.Consumer; import java.lang.reflect.Proxy; public class JdkProxy implements ProxyFactory { private Consumer consumer; public JdkProxy(Consumer consumer) { this.consumer = consumer; } //获取代理对象 @Override public T getProxy(Class clazz) { ClassLoader classLoader = clazz.getClassLoader(); Class[] interfaces = new Class[]{clazz}; return (T) Proxy.newProxyInstance(classLoader, interfaces, new ObjectProxy(consumer,clazz)); } }
在 com.xpc.consumer.spring.scanner.reference.ReferenceScanner中,我们扫描到有成员变量被@DubboReference注解标记,那么我们就要为这个接口生成代理对象,并注入到这个变量中去
package com.xpc.consumer.spring.scanner.reference; import com.xpc.consumer.spring.config.RpcConsumerAutoConfig; import com.xpc.consumer.spring.scanner.ClassScanner; import com.xpc.rpc.annotation.DubboReference; import com.xpc.rpc.consumer.RpcConsumer; import com.xpc.rpc.proxy.jdk.JdkProxy; import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.lang.reflect.Field; import java.util.List; public class ReferenceScanner extends ClassScanner { private static final Logger LOGGER = LoggerFactory.getLogger(ReferenceScanner.class); public void doScanDubboReferenceByPackage(String packageName) throws Exception{ // 其它代码省略 classList.forEach(item -> { try { Class clazz = Class.forName(item); Field[] clazzFields = clazz.getDeclaredFields(); for(Field field : clazzFields) { DubboReference dubboReference = field.getAnnotation(DubboReference.class); if(dubboReference != null) { Class targetClazz = field.getType(); JdkProxy jdkProxy = new JdkProxy(RpcConsumer.getInstance()); //获取这个接口的代理对象 Object proxy = jdkProxy.getProxy(targetClazz); //将代理对象设置到这个变量中去 setField(field, RpcConsumerAutoConfig.getObject(clazz),proxy,true); } } } catch (Exception e) { e.printStackTrace(); } }); } /** * 设置类的属性值 * * @param field 成员变量 * @param target 类实例 * @param value 成员变量的值 * @param accessible 是否允许设置私有属性 */ public static void setField(Field field, Object target, Object value,boolean accessible){ try { //是否允许设置私有的成员变量的值 field.setAccessible(accessible); field.set(target,value); } catch (IllegalAccessException e) { throw new RuntimeException(e); } } }