参考答案
CGLIB 动态代理的实现原理
- 利用asm开源包,对代理对象类的class文件加载进来,通过修改其字节码生成子类来处理。
CGLIB 动态代理的实现步骤
-
先实现一个 MethodInterceptor,方法调用会被转发到该类的intercept() 方法。 -
在要使用时,通过 CGLIB 动态代理,来获取代理对象。
CGLIB 动态代理的实现源码实例
public class HelloService { public HelloService() { System.out.println("HelloService构造"); } /** * 该方法不能被子类覆盖,Cglib是无法代理final修饰的方法的 */ final public String sayOthers(String name) { System.out.println("HelloService:sayOthers>>"+name); return null; } public void sayHello() { System.out.println("HelloService:sayHello"); } }
import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy; import java.lang.reflect.Method; /** * 自定义MethodInterceptor */ public class MyMethodInterceptor implements MethodInterceptor{ /** * sub:cglib生成的代理对象 * method:被代理对象方法 * objects:方法入参 * methodProxy: 代理方法 */ @Override public Object intercept(Object sub, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { System.out.println("======插入前置通知======"); Object object = methodProxy.invokeSuper(sub, objects); System.out.println("======插入后者通知======"); return object; } }
import net.sf.cglib.core.DebuggingClassWriter; import net.sf.cglib.proxy.Enhancer; public class Client { public static void main(String[] args) { // 代理类class文件存入本地磁盘方便我们反编译查看源码 System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "D:\\code"); // 通过CGLIB动态代理获取代理对象的过程 Enhancer enhancer = new Enhancer(); // 设置enhancer对象的父类 enhancer.setSuperclass(HelloService.class); // 设置enhancer的回调对象 enhancer.setCallback(new MyMethodInterceptor()); // 创建代理对象 HelloService proxy= (HelloService)enhancer.create(); // 通过代理对象调用目标方法 proxy.sayHello(); } }
CGLIB 代理时,做了以下操作:
-
生成的代理类继承被代理类。注:如委托类被final修饰,则不可被继承(被代理);同样,如委托类中存在final修饰的方法,则该方法也不可被代理。 -
代理类会为委托方法生成两个方法,一个是与委托方法签名相同的方法,它在方法中会通过 super
调用委托方法;另一个是代理类独有的方法 -
执行代理对象的方法时,先判断是否存在实现了 MethodInterceptor
接口的CGLIB$CALLBACK_0
; 如存在,则将调用MethodInterceptor
中的intercept
方法。
intercept
方法中,除了会调用委托方法,还会进行一些增强操作。在Spring AOP 中。典型的应用场景,是在某些敏感方法执行前后,进行操作日志记录。在 CGLIB 中,方法的调用不是通过反射来完成的,是直接对方法进行调用,通过 FastClass 机制对 Class 对象进行特别的处理。例如,用数组保存 method 的引用,每次调用方法时,都通过一个 index 下标,来保持对方法的引用。
以上,是Java面试题【CGLIB代理的实现、以及使用案例(代码实例)】的参考答案。
输出,是最好的学习方法。
欢迎在评论区留下你的问题、笔记或知识点补充~
—end—