v2.7
更新:实现CGLIB动态代理
-
实现CGLIB动态代理
-
实现一下统一调用代理类,创建总调用类,和对应模板接口,调用注解,同时在每个consumerbootstrap进行修改
-
对应模板接口
package consumer.proxy; //模板 public interface ClientProxy { public Object getBean(final Class<?> serviceClass); }
-
总调用类(通过SPI机制进行调用) //用户千万要注意当你选用的是nio的话千万只能用nio的方法
-
SPI机制对应配置 存放实现类的全限定名和实现类
-
SPI工具箱
package consumer.proxy; import exception.RpcException; import java.util.ServiceLoader; public class SPIClientProxyUtils { public static ClientProxy getUtils() throws RpcException { ServiceLoader<ClientProxy> loader = ServiceLoader.load(ClientProxy.class); for (ClientProxy clientProxy : loader) { return clientProxy; } throw new RpcException("您键入的代理,并未实现,欢迎实现提出pr"); } }
-
-
-
实现CGLIB动态代理
-
依赖引入
<!--CGLIB依赖引入--> <dependency> <groupId>cglib</groupId> <artifactId>cglib</artifactId> <version>3.3.0</version> </dependency>
-
构建代理类实现代码
package consumer.proxy.netty; import annotation.RegistryChosen; import consumer.netty.NettyClient; import consumer.proxy.ClientProxy; import consumer.service_discovery.NacosServiceDiscovery; import consumer.service_discovery.ZkCuratorDiscovery; import consumer.service_discovery.ZkServiceDiscovery; import exception.RpcException; import net.sf.cglib.proxy.Enhancer; import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy; import register.Register; import java.lang.reflect.Method; //Cglib实现代理模式 public class RpcNettyClientCGLIBProxy implements ClientProxy,MethodInterceptor{ @Override public Object getBean(Class serviceClass) { //设置动态代理增强类 Enhancer enhancer = new Enhancer(); //设置类加载器 // enhancer.setClassLoader(serviceClass.getClassLoader()); //设置代理类 enhancer.setSuperclass(serviceClass); //设置对应的方法执行拦截器,方法回调 enhancer.setCallback(this); return enhancer.create(); } /** * @param obj 代理对象(增强的对象) * @param method 被拦截的方法(需要增强的方法) * @param args 方法入参 * @param methodProxy 用于调用原始方法 */ @Override //自定义对应的拦截 拦截方法并执行别的任务 public Object intercept(Object obj, Method method, Object[] args, MethodProxy methodProxy) throws Throwable { String methodAddress = getMethodAddress(method.getName()); String[] split = methodAddress.split(":"); return NettyClient.callMethod(split[0],Integer.valueOf(split[1]),args[0],method); } /** * 实际去获得对应的服务 并完成方法调用的方法 * @param methodName 根据方法名 根据添加的注册中心注解来选择相应的注册中心进行 实现负载均衡获取一个方法对应地址 * @param * @return */ private static String getMethodAddress(String methodName) throws Exception { //根据注解进行方法调用 //根据在代理类上的注解调用 看清楚底下的因为是个class数组 可以直接继续获取 注解 RegistryChosen annotation = Register.class.getAnnotation(RegistryChosen.class); switch (annotation.registryName()) { case "nacos": return NacosServiceDiscovery.getMethodAddress(methodName); case "zookeeper": return ZkServiceDiscovery.getMethodAddress(methodName); case "zkCurator": return ZkCuratorDiscovery.getMethodAddress(methodName); default: throw new RpcException("不存在该注册中心"); } } }
-
-
BUG
-
问题
-
解决
追进去看CGLIB构建代理类源码 是什么原因造成的这个错误,同时别人也是可以代理接口的啊
JDK动态代理代理接口,cglib可以代理类和接口
- 经过验证 应该是和我们传进去的方法无关的
- 找到错误了 进行创建应该是enhancer.create()方法 我给写成了enhancer.createClass()
-
-
-
问题声明
在调用方法这边这么写的原因是,无法获取对应调用类上的版本信息,会导致循环依赖,如果读者想更简单调用每个版本都对应一个对应的NettyClient的类 可以直接通过对应的NettyClient进行调用