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