参考答案
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—