一文读懂Java中的动态代理 (4)

(3) 生成代理对象,并测试代理是否生效

public static void main(String[] args) { // 指定目录生成动态代理类class文件 System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "/tmp/cglib"); Enhancer enhancer = new Enhancer(); // set the class which the generated class will extend enhancer.setSuperclass(OrderService.class); // set the single Callback to use enhancer.setCallback(new LogInterceptor()); // generate a new class OrderService proxy = (OrderService) enhancer.create(); proxy.query(1L); System.out.println(); proxy.delete(1L); }

(4) 运行结果

开始处理请求时间: 1594653500162 查询到订单:1 结束处理请求时间: 1594653500183 已删除订单:1

可见,对OrderService的query()方法实现了代理,而被final修饰的delete()方法没有被代理。

实现原理

非常类似学习JDK的动态代理,这里我们同样反编译生成的代理class文件,去除其他暂时这里不关注的信息,代码如下:

import java.lang.reflect.Method; import net.sf.cglib.core.ReflectUtils; import net.sf.cglib.core.Signature; import net.sf.cglib.proxy.Callback; import net.sf.cglib.proxy.Factory; import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy; public class OrderService$$EnhancerByCGLIB$$ba8463fa extends OrderService implements Factory { private static final Method CGLIB$query$0$Method; private static final MethodProxy CGLIB$query$0$Proxy; static void CGLIB$STATICHOOK1() { CGLIB$query$0$Method = ReflectUtils.findMethods(new String[]{"query", "(Ljava/lang/Long;)Ljava/lang/Object;"}, (var1 = Class.forName("com.github.itwild.proxy.OrderService")).getDeclaredMethods())[0]; CGLIB$query$0$Proxy = MethodProxy.create(var1, var0, "(Ljava/lang/Long;)Ljava/lang/Object;", "query", "CGLIB$query$0"); } final Object CGLIB$query$0(Long var1) { return super.query(var1); } public final Object query(Long var1) { MethodInterceptor var10000 = this.CGLIB$CALLBACK_0; if (var10000 == null) { CGLIB$BIND_CALLBACKS(this); var10000 = this.CGLIB$CALLBACK_0; } return var10000 != null ? var10000.intercept(this, CGLIB$query$0$Method, new Object[]{var1}, CGLIB$query$0$Proxy) : super.query(var1); } public static MethodProxy CGLIB$findMethodProxy(Signature var0) { String var10000 = var0.toString(); switch(var10000.hashCode()) { case -508378822: if (var10000.equals("clone()Ljava/lang/Object;")) { return CGLIB$clone$4$Proxy; } break; case 842547398: if (var10000.equals("query(Ljava/lang/Long;)Ljava/lang/Object;")) { return CGLIB$query$0$Proxy; } break; case 1826985398: if (var10000.equals("equals(Ljava/lang/Object;)Z")) { return CGLIB$equals$1$Proxy; } break; case 1913648695: if (var10000.equals("toString()Ljava/lang/String;")) { return CGLIB$toString$2$Proxy; } break; case 1984935277: if (var10000.equals("hashCode()I")) { return CGLIB$hashCode$3$Proxy; } } return null; } static { CGLIB$STATICHOOK1(); } }

观察OrderService$$EnhancerByCGLIB$$ba8463fa得知该类继承了OrderService,并且override了query(Long id)方法,而delete方法被final修饰不能被重写。

到了这里,不知道你有没有想起开篇讲到的实现代理模式的第二种方式(代理类继承目标类,重写需要代理的方法)。这里应用的正是这种。

关于cglib更详细的介绍并不是这里的重点,后面我会抽时间细致学习学习做个笔记出来。不过这里还是要多提几句。

当调用代理类的query()方法时,会寻找该query()方法上有没有被绑定拦截器(比如说编写代码时实现的MethodInterceptor接口),没有的话则不需要代理。JDK动态代理的拦截对象是通过反射的机制来调用被拦截方法的,反射的效率较低,cglib采用了FastClass的机制来实现对被拦截方法的调用。FastClass机制会对一个类的方法建立索引,通过索引来直接调用相应的方法,提高了效率。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wsxyjj.html