Cglib的Enhancer类动态创建代理对象的的过程

使用Enhance字节码增强创建动态代理对象的一般步骤为:

Enhancre enhancer = new Enhancer();
enhancer.setSuperclass(目标对象的类对象);
enhancer.setCallback(new MethodInterceptor(){
			@Override
            public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
            }
});
目标类  o = (目标类)enhancer.create();//o为创建出来的代理对象

本文通过解析重要的源码对代理对象的创建过程进行梳理,其中cglib调用ASM框架生成字节码文件的过程本文不详细说明,若有机会,会另外写一篇关于AMS框架的相关内容。

创建代理对象过程图解

过程图解
根据上图,本文首先会对对象key做一个介绍,然后描述一下cglib代理过程的缓存结构。最后基于这两者来谈谈代理对象的创建过程。

Key

在动态代理中,一个代理类的生成不仅仅与目标类有关,还和与之关联的方法拦截器(MethodInterceptor)、过滤器(CallbackFilter)等等有关。这样的话就要使用multi-vaules key来标识这个生成类,在cglib中multi-vaules 也是动态生成的,KeyFactory 就是生成multi-vaules的工厂类,它是一个抽象类,也就是说它不能被实例化,但是它提供了一系列的静态工厂方法来生成multi-vaules的工厂类。
在Enhancer类中定义了一个内部接口:

public interface EnhancerKey {
        public Object newInstance(String type,
                                  String[] interfaces,
                                  WeakCacheKey<CallbackFilter> filter,
                                  Type[] callbackTypes,
                                  boolean useFactory,
                                  boolean interceptDuringConstruction,
                                  Long serialVersionUID);
    }

说明通过Enhancer来创建代理对象,需要用以上7个信息来标识。
总之一句话,key是代理类的一个标识之一,另一个标识就是类加载器(因为判断是否是同一个的前提是类加载器要一致)。所以,Key+ClassLoader是代理类唯一性的标识。

Cache缓存结构

所谓Cache是一种缓存机制,有助于提高动态代理的性能,也就是说之前生成过的代理类不需要再次生成,通过代理类的标识直接存缓存中提取即可。
cache结构
抽象类AbstractClassGenerator只有一个构造函数protected AbstractClassGenerator(Source source),入参是一个Source类型的对象,Source是AbstractClassGenerator里面的一个静态内部类,Source有两个字段 name用来记录class generator,cache 就是缓存,它和jdk动态代理一样都是用了WeakHashMap,并且类型也是<ClassLoader,<Object,Class>>。

protected static class Source {
        String name; //class generator的name,eg:如果使用Enhancer来生成增强类,name的值就为 net.sf.cglib.proxy. Enhancer
        Map cache = new WeakHashMap();
        public Source(String name) {
            this.name = name;
        }
}

代理类的创建流程

cglib有不同的class生成方法,以下针对Enhancer类进行阐述。
当我们执行enhancer.create()时,其方法调用栈为:
enhancer.create()—>createrHelper()—>AbstractClassGenerator.create(key)
为此我们下面着重分析AbstractClassGenerator的create方法。

protected Object create(Object key) {  
    try {  
        Class gen = null;  
          
        synchronized (source) {  
        	//获得类加载器
            ClassLoader loader = getClassLoader();
            //cache2为二级缓存Map  
            Map cache2 = null;  
            cache2 = (Map)source.cache.get(loader);
            //若该类加载器对应的二级缓存为空,那么new一个Map并添加  
            if (cache2 == null) {  
                cache2 = new HashMap();  
                cache2.put(NAME_KEY, new HashSet());  
                source.cache.put(loader, cache2);  
            } else if (useCache) {  //若不为空,根据key获取对应的代理类
                Reference ref = (Reference)cache2.get(key);  
                gen = (Class) (( ref == null ) ? null : ref.get());   
            }  
            if (gen == null) {  
                Object save = CURRENT.get();  
                CURRENT.set(this);  
                try {  
                    this.key = key;  
                      
                    if (attemptLoad) {  //attempLoad默认为false
                        try {  
                            gen = loader.loadClass(getClassName());  
                        } catch (ClassNotFoundException e) {  
                            // ignore  
                        }  
                    }  
                    if (gen == null) {  
                        //生成的Class的二进制存储  
                        byte[] b = strategy.generate(this);  
                        String className = ClassNameReader.getClassName(new ClassReader(b));  
                        //将类名放入Cache中,Cache实际上是一个Hashset的实例  
                        getClassNameCache(loader).add(className);  
                        //将生成的类装载路JVM  
                        gen = ReflectUtils.defineClass(className, b, loader);  
                    }  
                     
                    if (useCache) {  
                        //将装载的类放入cache  
                        cache2.put(key, new WeakReference(gen));  
                    }  
                    return firstInstance(gen);  
                } finally {  
                    CURRENT.set(save);  
                }  
            }  
        }  
        return firstInstance(gen);  
    } catch (RuntimeException e) {  
        throw e;  
    } catch (Error e) {  
        throw e;  
    } catch (Exception e) {  
        throw new CodeGenerationException(e);  
    }  
}  

流程图

参考

cglib源码分析(一): 缓存和KEY
Cglib学习札记

  • 5
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值