美文网首页spring
Spring源码学习(4) —— CglibAopProxy实现

Spring源码学习(4) —— CglibAopProxy实现

作者: shysheng | 来源:发表于2018-07-09 20:46 被阅读0次

    上一节我们分析了cglib方式实现aop的基本过程,本文将继续上一篇的内容,具体讲讲代理对象的实现细节。提到代理对象的产生,就不得不提Enhancer,这是cglib中的一个字节码增强器,通过它我们可以对目标类进行扩展。
    本文主要分析以下两个问题:
    1.cglib如何生成代理类
    2.cglib生成代理的方式中,哪些方法不能被代理
    3.cglib的二级缓存机制

    1.源码分析

    Enhancer中产生代理类的入口是几个签名不同的create()方法,但是这几个create()方法最终都会调用createHelper()方法,因此我们就从createHelper()方法着手:

    private Object createHelper() {
        // 这里主要是一些参数校验,比较简单
        this.preValidate();
    
        // 根据代理配置生成缓存的key,作为二级缓存的key值,而一级缓存的key则是ClassLoader
        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;
    
        // 调用父类AbstractClassGenerator的create()方法
        Object result = super.create(key);
        return result;
    }
    

    AbstractClassGenerator是cglib中一个很重要的类,是字节码生成过程中的一个核心调度者,包括缓存、命名策略、字节码生成策略都由它定义,Enhancer就是它的一个子类。

    protected Object create(Object key) {
        try {
            // 获取类加载器
            ClassLoader loader = this.getClassLoader();
            Map<ClassLoader, AbstractClassGenerator.ClassLoaderData> cache = CACHE;
    
            // 优先从缓存加载,根据ClassLoader区分
            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);
        } 
    ... 异常处理省略
    }
    

    类加载器是按照如下顺序来获取的:加载父类或者接口的类加载器 -> 自己的类加载器 -> 线程上下文类加载器,这个过程在上一篇也有提到,这里不再展开。

    缓存在这个构造函数中进行初始化:

    protected static class ClassLoaderData {
        public ClassLoaderData(ClassLoader classLoader) {
            if(classLoader == null) {
                throw new IllegalArgumentException("classLoader == null is not yet supported");
            } else {
                this.classLoader = new WeakReference(classLoader);
                Function<AbstractClassGenerator, Object> load = new Function<AbstractClassGenerator, Object>() {
                    public Object apply(AbstractClassGenerator gen) {
    
                        // 产生字节码文件
                        Class klass = gen.generate(ClassLoaderData.this);
                        return gen.wrapCachedClass(klass);
                    }
                };
    
                // 生成二级缓存
                this.generatedClasses = new LoadingCache(GET_KEY, load);
            }
        }
    
        // 判断是否使用缓存
        public Object get(AbstractClassGenerator gen, boolean useCache) {
            if(!useCache) {
                return gen.generate(this);
            } else {
                // 从二级缓存中取出代理对象
                Object cachedValue = this.generatedClasses.get(gen);
                return gen.unwrapCachedValue(cachedValue);
            }
        }
    }
    
    protected Class generate(AbstractClassGenerator.ClassLoaderData data) {
        Object save = CURRENT.get();
        CURRENT.set(this);
    
        try {
            ClassLoader classLoader = data.getClassLoader();
            if(classLoader == null) {
                throw new IllegalStateException("ClassLoader is null while trying to define class " + this.getClassName() + ". It seems that the loader has been expired from a weak reference somehow. Please file an issue at cglib's issue tracker.");
            } else {
                String className;
                synchronized(classLoader) {
                    // 根据命名策略生成代理类类名
                    className = this.generateClassName(data.getUniqueNamePredicate());
                    data.reserveName(className);
                    this.setClassName(className);
                }
    
                Class gen;
                if(this.attemptLoad) {
                    try {
                        gen = classLoader.loadClass(this.getClassName());
                        Class var25 = gen;
                        return var25;
                    } catch (ClassNotFoundException var20) {
                        ;
                    }
                }
    
                // 生成二进制流,默认实现DefaultGeneratorStrategy
                byte[] b = this.strategy.generate(this);
                className = ClassNameReader.getClassName(new ClassReader(b));
                ProtectionDomain protectionDomain = this.getProtectionDomain();
                synchronized(classLoader) {
                    if(protectionDomain == null) {
                        // 根据二进制流生成字节码
                        gen = ReflectUtils.defineClass(className, b, classLoader);
                    } else {
                        gen = ReflectUtils.defineClass(className, b, classLoader, protectionDomain);
                    }
                }
    
                Class var8 = gen;
                return var8;
            }
        }
    ... 省略异常处理
    

    生成代理类类名的具体逻辑如下:

    public String getClassName(String prefix, String source, Object key, Predicate names) {
        // prefix一般就是目标类的全限定名
        if(prefix == null) {
            prefix = "org.springframework.cglib.empty.Object";
        } else if(prefix.startsWith("java")) {
            prefix = "$" + prefix;
        }
    
        // source就是Enhancer的全限定名
        // source.substring(source.lastIndexOf(46) + 1)就是去Enhancer的简称
        // this.getTag()返回的是"ByCGLIB"
        String base = prefix + "$$" + source.substring(source.lastIndexOf(46) + 1) + this.getTag() + "$$" + Integer.toHexString(STRESS_HASH_CODE?0:key.hashCode());
        String attempt = base;
    
        for(int var7 = 2; names.evaluate(attempt); attempt = base + "_" + var7++) {
            ;
        }
    
        return attempt;
    }
    
    public class DefaultGeneratorStrategy implements GeneratorStrategy {
    
        public byte[] generate(ClassGenerator cg) throws Exception {
            DebuggingClassWriter cw = this.getClassVisitor();
            this.transform(cg).generateClass(cw);
            return this.transform(cw.toByteArray());
        }
    }
    

    利用Enhancer来生成代理类,底层也是采用了asm框架,具体实现如下:

    public void generateClass(ClassVisitor v) throws Exception {
        Class sc = this.superclass == null?Object.class:this.superclass;
        if(TypeUtils.isFinal(sc.getModifiers())) {
            throw new IllegalArgumentException("Cannot subclass final class " + sc.getName());
        } else {
            List constructors = new ArrayList(Arrays.asList(sc.getDeclaredConstructors()));
            this.filterConstructors(sc, constructors);
            List actualMethods = new ArrayList();
            List interfaceMethods = new ArrayList();
            final Set forcePublic = new HashSet();
    
            // 采用递归的方式,找到目标类的父类、接口的所有方法,并过滤掉满足条件的方法,具体条件后文有详细说明
            getMethods(sc, this.interfaces, actualMethods, interfaceMethods, forcePublic);
    
            // 对方法的修饰符作了变化,保存到methods中,转换之前的方法保存在actualMethods中
            List methods = CollectionUtils.transform(actualMethods, new Transformer() {
                public Object transform(Object value) {
                    Method method = (Method)value;
                    // 在Modifier类中,1024、256、32、16分别表示abstract、native、synchronized、final修饰符,因此这句话的意思是将abstract、native、synchronized修饰符全部去掉,然后加上final修饰符
                    int modifiers = 16 | method.getModifiers() & -1025 & -257 & -33;
                    // 同理,这里是把protected修饰符换成public
                    if(forcePublic.contains(MethodWrapper.create(method))) {
                        modifiers = modifiers & -5 | 1;
                    }
    
                    return ReflectUtils.getMethodInfo(method, modifiers);
                }
            });
    
            // 这里有一段是根据asm框架产生字节码了,还没看懂,先跳过o(╯□╰)o
            ......
    
            if(this.currentData == null) {
                // 上一篇讲过,CallbackFilter作为回调过滤器,其核心方法为accept(),返回值为int类型,代表了回调入口在callbacks数组中的位置,这里就是完成了CallbackFilter的处理,确定每个方法分别有哪个过滤器来处理
                this.emitMethods(e, methods, actualMethods);
                this.emitConstructors(e, constructorInfo);
            } else {
                this.emitDefaultConstructor(e);
            }
    
            ......
    
            e.end_class();
        }
    }
    

    getMethods方法具体实现逻辑:

    private static void getMethods(Class superclass, Class[] interfaces, List methods, List interfaceMethods, Set forcePublic) {
        // 递归添加父类的所有方法
        ReflectUtils.addAllMethods(superclass, methods);
        List target = interfaceMethods != null?interfaceMethods:methods;
    
        // 递归添加接口的所有方法
        if(interfaces != null) {
            for(int i = 0; i < interfaces.length; ++i) {
                if(interfaces[i] != Factory.class) {
                    ReflectUtils.addAllMethods(interfaces[i], target);
                }
            }
        }
    
        if(interfaceMethods != null) {
            if(forcePublic != null) {
                forcePublic.addAll(MethodWrapper.createSet(interfaceMethods));
            }
    
            methods.addAll(interfaceMethods);
        }
    
        // 过滤掉静态方法,在Modifier类中,静态方法的标识就是0x00000008
        CollectionUtils.filter(methods, new RejectModifierPredicate(8));
        // 过滤掉不可见的方法(包括两类:私有方法、默认修饰符且与目标类不在同一个包中的方法)
        CollectionUtils.filter(methods, new VisibilityPredicate(superclass, true));
        // 过滤掉重复的方法(方法名、入参和返回类型都相同的方法)
        CollectionUtils.filter(methods, new DuplicatesPredicate());
        // 过滤掉final方法,在Modifier类中,静态方法的标识就是0x00000010
        CollectionUtils.filter(methods, new RejectModifierPredicate(16));
    }
    

    emitMethods方法具体实现逻辑:

    private void emitMethods(ClassEmitter ce, List methods, List actualMethods) {
        CallbackGenerator[] generators = CallbackInfo.getGenerators(this.callbackTypes);
        Map groups = new HashMap();
        final Map indexes = new HashMap();
        final Map originalModifiers = new HashMap();
        final Map positions = CollectionUtils.getIndexMap(methods);
        Map declToBridge = new HashMap();
        Iterator it1 = methods.iterator();
        Iterator it2 = actualMethods != null?actualMethods.iterator():null;
    
        while(it1.hasNext()) {
            MethodInfo method = (MethodInfo)it1.next();
            Method actualMethod = it2 != null?(Method)it2.next():null;
    
            // 选择具体的回调过滤器
            int index = this.filter.accept(actualMethod);
            if(index >= this.callbackTypes.length) {
                throw new IllegalArgumentException("Callback filter returned an index that is too large: " + index);
            }
    
            // 把方法和其对应的修饰符的映射关系保存起来
            originalModifiers.put(method, new Integer(actualMethod != null?actualMethod.getModifiers():method.getModifiers()));
            // 把方法和其对应的回调过滤器下表的映射关系保存起来
            indexes.put(method, new Integer(index));
            List group = (List)groups.get(generators[index]);
            if(group == null) {
                groups.put(generators[index], group = new ArrayList(methods.size()));
            }
            ((List)group).add(method);
    
            // 建立类和桥接方法之间的映射关系
            // 桥接方法:jdk1.5引入了泛型,并且在编译期会进行类型擦除,因此字节码文件中集合元素类型都是Object,同时由于对类型的校验也提前到了编译期,因此编译期会生成一个桥接方法,将Object类型转换为实际类型。
            if(TypeUtils.isBridge(actualMethod.getModifiers())) {
                Set bridges = (Set)declToBridge.get(actualMethod.getDeclaringClass());
                if(bridges == null) {
                    bridges = new HashSet();
                    declToBridge.put(actualMethod.getDeclaringClass(), bridges);
                }
    
                ((Set)bridges).add(method.getSignature());
            }
        }
    
        // 又是一堆根据asm生成字节码的逻辑,暂时略过o(╯□╰)o
        ......
    }
    

    2.测试

    好了,源码总是虚无缥缈的,我们接下来举一个实际的栗子来看一看。

    目标类:

    public class Target {
    
        public void exeTarget() {
            System.out.println("execute target.");
        }
    }
    

    增强类:

    public class BeforeAdvice implements MethodBeforeAdvice {
    
        public void before(Method method, Object[] objects, Object o) throws Throwable {
            System.out.println("before advice.");
        }
    }
    

    配置文件:

    <bean id="adviceSeq" class="org.springframework.aop.framework.ProxyFactoryBean"
          p:target-ref="target"
          p:proxyTargetClass="true"
          p:frozen="true"
          p:interceptorNames="beforeAdvice"/>
    

    测试类:

    public class AdviceSeqTest {
    
        public static void main(String[] args) {
    
            // 将产生的代理类文件写入磁盘
            System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, ".//");
            String configPath = "advice/seq/beans.xml";
            ApplicationContext context = new ClassPathXmlApplicationContext(configPath);
            Target target = (Target) context.getBean("adviceSeq");
            target.exeTarget();
        }
    }
    

    运行测试类后,得到的代理类class文件名为Target$$EnhancerBySpringCGLIB$$8b53f595.class,跟我们前面的分析一致,目标方法的代理方法为如下,静态方法exeStaticTarget()、私有privateMethod()和final方法finalMethod()在生成的代理类中都不存在:

    // 跟之前分析的一样,方法加上了final修饰符
    public final void exeTarget() {
        try {
            MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
            if(this.CGLIB$CALLBACK_0 == null) {
                CGLIB$BIND_CALLBACKS(this);
                var10000 = this.CGLIB$CALLBACK_0;
            }
    
            // 如果回调函数不为空,执行拦截,否则直接调用目标方法
            if(var10000 != null) {
                var10000.intercept(this, CGLIB$exeTarget$6$Method, CGLIB$emptyArgs, CGLIB$exeTarget$6$Proxy);
            } else {
                super.exeTarget();
            }
        } catch (Error | RuntimeException var1) {
            throw var1;
        } catch (Throwable var2) {
            throw new UndeclaredThrowableException(var2);
        }
    }
    

    相关文章

      网友评论

        本文标题:Spring源码学习(4) —— CglibAopProxy实现

        本文链接:https://www.haomeiwen.com/subject/wyaifftx.html