动态代理-CGLIB

image.png

新建了一个Springboot项目编写demo:

  1. 创建Enhancer增强器,设置参数:是否使用缓存、代理哪个类、方法拦截器,这里的MethodInterceptor和JDK动态代理中的InvocationHandler作用类似;
  2. 因为我用Lamda创建的,所以没有显示出MethodInterceptor实现的方法intercept(),和InvocationHandler的invoke方法一样。其中前三个参数相同,不同的是MethodInterceptor有第四个参数MethodProxy;
  3. 通过methodProxy的invokeSuper方法才能调用目标对象的方法;
  4. 然后通过enhancer.create() 创建一个实例对象。
public class CglibTest2 {
    public static void main(String[] args) {

        //System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY,"D:\workspace\test\cdliByte");
        Enhancer enhancer = new Enhancer();
        enhancer.setUseCache(false);
        enhancer.setSuperclass(TargetBean.class);
        //匿名内部类 Lamda形式创建一个MethodInterceptor接口实例对象
        enhancer.setCallback((MethodInterceptor) (o, method, objects, methodProxy) -> {
            System.out.println("执行前");
            //jdk动态代理:因为我们的目标类有实现接口,我们可以通过jdk的Method的invoke调用目标方法
            //Object ob = method.invoke(new TargetBean2(), args);

            //cglib:调用methodProxy的invoke、invokeSuper方法
            //invoke()是调用增强后的方法 会死循环 内存溢出、invokeSuper()会调用目标类的方法
            //Object ob = methodProxy.invoke(o, args);

            Object ob = methodProxy.invokeSuper(o, args);
            System.out.println("执行后");
            return ob;
        });

        TargetBean2 bean = (TargetBean2)enhancer.create();
        bean.test();
    }
}
interface  InterfaceBean{
    void test();
}
class TargetBean implements InterfaceBean{
    @Override
    public void test(){
        System.out.println("我是目标类");
    }
}

调用流程

  1. 直接看enhancer.create(),进去之后调用了this.createHelper(),生成一个EnhancerKey对象,里面保存了用户设置的代理信息,然后调用父类AbstractClassGenerator的creat方法;
  2. 通过ClassLoaderData 的get方法从缓存中获取代理类,this.getUseCache()参数就是我们demo中的enhancer.setUseCache(false)设置的boolean值,然后调用代理类的构造方法生成一个代理对象;
  3. 两个instance方法最终都会调用 ReflectUtils.newInstance(type, this.argumentTypes, this.arguments), 并且通过方法setThreadCallbacks(type, this.callbacks)设置callback到代理类中的一个TheadLocal中,代理类在调用方法时,就可以直接用我们自定义的MethodInterceptor中增强的内容。
    public Object create() {
        this.classOnly = false;
        this.argumentTypes = null;
        return this.createHelper();
    }
    private Object createHelper() {
        this.preValidate();
        Object key = KEY_FACTORY.newInstance(this.superclass != null ? this.superclass.getName() : null, ReflectUtils.getNames(this.interfaces), this.filter == ALL_ZERO ? null : new WeakCacheKey(this.filter), this.callbackTypes, this.useFactory, this.interceptDuringConstruction, this.serialVersionUID);
        this.currentKey = key;
        Object result = super.create(key);
        return result;
    }

protected Object create(Object key) {
        try {
            ClassLoader loader = this.getClassLoader();
            Map<ClassLoader, AbstractClassGenerator.ClassLoaderData> cache = CACHE;
            AbstractClassGenerator.ClassLoaderData data = (AbstractClassGenerator.ClassLoaderData)cache.get(loader);
            if (data == null) {
                Class var5 = AbstractClassGenerator.class;
                synchronized(AbstractClassGenerator.class) {
                    cache = CACHE;
                    data = (AbstractClassGenerator.ClassLoaderData)cache.get(loader);
                    if (data == null) {
                        Map<ClassLoader, AbstractClassGenerator.ClassLoaderData> newCache = new WeakHashMap(cache);
                        data = new AbstractClassGenerator.ClassLoaderData(loader);
                        newCache.put(loader, data);
                        CACHE = newCache;
                    }
                }
            }
            this.key = key;
            //获取代理类
            Object obj = data.get(this, this.getUseCache());
            //生成代理类对象
            return obj instanceof Class ? this.firstInstance((Class)obj) : this.nextInstance(obj);
        } catch (Error | RuntimeException var9) {
            throw var9;
        } catch (Exception var10) {
            throw new CodeGenerationException(var10);
        }
    }

MethodProxy底层

  1. 前面提到调用methodProxy的invoke()是调用增强后的方法,会死循环内存溢出,invokeSuper()会调用目标类的方法;
  2. 通过设置System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY,"D:\workspace\test\cdliByte")可以在对应目录下生成代理类的字节码文件,查看字节码文件的test方法能够看到methodProxy对象是由MethodProxy.create()方法创建的;
  3. invoke和invokeSuper方法都会执行this.init()来给FastClassInfo赋值,f1和f2分别为两个类的fastclass代理类,i1和i2是两个类中方法下标,以及生成fastclass代理类的字节码文件;
  4. 然后通过FastClassInfo对象执行目标类/代理类的方法,invoke(fci.i2, obj, args) 则会根据方法下标执行fastclass类中对应下标的方法。

image.png

生成的代理类和两个fastclass类的字节码文件如下:

image.png

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值