Spring源码学习(4) —— CglibAopProxy实现AOP之Enhancer源码解析

上一节我们分析了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 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 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 load = new Function() {
                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.");
    }
}

配置文件:


测试类:

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实现AOP之Enhancer源码解析)