playground

Cglib

版本

先看一个简单的Cglib动态代理的例子。

class Proxied {

    public void f() {
        System.out.println("Proxied");
    }
}

class ProxyInterceptor implements MethodInterceptor {

    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("Proxy");
        methodProxy.invokeSuper(o, objects);
        return o;
    }
}

public static void main(String[] args) {
    Enhancer enhancer = new Enhancer();
    enhancer.setSuperclass(Proxied.class);
    enhancer.setCallback(new ProxyInterceptor());
    Proxied proxy = (Proxied) enhancer.create();
    proxy.f(); //此处打印“Proxy”,“Proxied”。
}

从使用方法来看,对比JDK自己的动态代理,Cglib的动态代理不需要被代理类实现接口,使用起来更加方便。下面我们来看下它的实现原理。

很显然,创建代理类的入口就是下面这行代码。

enhancer.create();

在它的内部主要调用了下面的方法,并且直接返回该方法的返回值。

// net.sf.cglib.proxy.Enhancer#createHelper
private Object createHelper() {
    // 验证Enhancer对象的各个参数是否合法。
    this.validate(false);
    if (this.superclass != null) {
        this.setNamePrefix(this.superclass.getName());
    } else if (this.interfaces != null) {
        this.setNamePrefix(this.interfaces[ReflectUtils.findPackageProtected(this.interfaces)].getName());
    }

    // 根据当前对象的一些字段生成一个组合键,这个键用来从缓存中读取或写入。
    Object key = KEY_FACTORY.newInstance(this.superclass, this.interfaces, this.filter, this.callbackTypes, this.useFactory);
    return super.create(key);
}

// net.sf.cglib.core.AbstractClassGenerator#create
// 该方法定义在Enhancer的基类中。
protected Object create(Object key) {
    try {
        Object instance = null;
        AbstractClassGenerator.Source var3 = this.source;
        synchronized(this.source) {
            ClassLoader loader = this.getClassLoader();
            Map cache2 = null;
            // ClassLoader为键的一级缓存。
            cache2 = (Map)this.source.cache.get(loader);
            if (cache2 == null) {
                cache2 = new HashMap();
                ((Map)cache2).put(NAME_KEY, new HashSet());
                this.source.cache.put(loader, cache2);
            } else if (this.useCache) {
                // 缓存中存储的是软引用。
                Reference ref = (Reference)((Map)cache2).get(key);
                instance = ref == null ? null : ref.get();
            }

            if (instance == null) {
                Object save = CURRENT.get();
                // 把当前对象存在ThreadLocal中,它的作用是可以通过一个静态方法获取当前的AbstractClassGenerator对象。
                // public static AbstractClassGenerator getCurrent() {return (AbstractClassGenerator)CURRENT.get();}
                CURRENT.set(this);

                Object var25;
                try {
                    this.key = key;
                    Class gen = null;
                    // 如果this.attemptLoad是true,则会尝试去加载类,默认是false。
                    if (this.attemptLoad) {
                        try {
                            gen = loader.loadClass(this.getClassName());
                        } catch (ClassNotFoundException var18) {
                            ;
                        }
                    }

                    if (gen == null) {
                        // 使用一种生成策略生成类对应的字节码。
                        byte[] b = this.strategy.generate(this);
                        String className = ClassNameReader.getClassName(new ClassReader(b));
                        this.getClassNameCache(loader).add(className);
                        // 根据字节码定义类。
                        gen = ReflectUtils.defineClass(className, b, loader);
                    }

                    // 获取类的实例。
                    instance = this.firstInstance(gen);
                    if (this.useCache) {
                        // 缓存实例,这里用的是软引用。
                        ((Map)cache2).put(key, new SoftReference(instance));
                    }

                    var25 = instance;
                } finally {
                    CURRENT.set(save);
                }

                return var25;
            }
        }
        // 如果缓存命中并且软引用还没有被GC清理,那么就直接通过缓存中的实例拿到Class对象并用反射创建新的实例。
        return this.nextInstance(instance);
    } catch (RuntimeException var21) {
        throw var21;
    } catch (Error var22) {
        throw var22;
    } catch (Exception var23) {
        throw new CodeGenerationException(var23);
    }
}

可以看到动态生成代理类的关键方法是this.strategy.generate(this),生成策略的默认实现类是net.sf.cglib.core.DefaultGeneratorStrategy,而它的内部又调用了net.sf.cglib.core.ClassGenerator接口生成字节码,最后的方法其实就在Enhancer类中。

// net.sf.cglib.core.DefaultGeneratorStrategy#generate
public byte[] generate(ClassGenerator cg) throws Exception {
    ClassWriter cw = this.getClassWriter();
    // 构建代理类的字节码。
    this.transform(cg).generateClass(cw);
    // 字节码输出到字节数组。
    return this.transform(cw.toByteArray());
}

// net.sf.cglib.proxy.Enhancer#generateClass
public void generateClass(ClassVisitor v) throws Exception {
    Class sc = this.superclass == null ? (class$java$lang$Object == null ? (class$java$lang$Object = class$("java.lang.Object")) : class$java$lang$Object) : this.superclass;
    // Cglib中代理类需要继承被代理类,因此被代理类不能是final的。
    if (TypeUtils.isFinal(sc.getModifiers())) {
        throw new IllegalArgumentException("Cannot subclass final class " + sc);
    } else {
        this.depth = calculateDepth(sc);
        List constructors = new ArrayList(Arrays.asList(sc.getDeclaredConstructors()));
        // 找到所有非私有的构造方法。
        CollectionUtils.filter(constructors, new VisibilityPredicate(sc, true));
        if (constructors.size() == 0) {
            throw new IllegalArgumentException("No visible constructors in " + sc);
        } else {
            ClassEmitter e = new ClassEmitter(v);
            // 开始生成代理类,内部使用ASM技术。
            e.begin_class(1, this.getClassName(), Type.getType(sc), this.useFactory ? TypeUtils.add(TypeUtils.getTypes(this.interfaces), FACTORY) : TypeUtils.getTypes(this.interfaces), "<generated>");
            List actualMethods = new ArrayList();
            List interfaceMethods = new ArrayList();
            final Set forcePublic = new HashSet();
            // 找出需要在代理类中生成的方法。
            getMethods(sc, this.interfaces, actualMethods, interfaceMethods, forcePublic);
            List methods = CollectionUtils.transform(actualMethods, new Transformer() {
                public Object transform(Object value) {
                    Method method = (Method)value;
                    int modifiers = 16 | method.getModifiers() & -1025 & -257 & -33;
                    if (forcePublic.contains(MethodWrapper.create(method))) {
                        modifiers = modifiers & -5 | 1;
                    }

                    return ReflectUtils.getMethodInfo(method, modifiers);
                }
            });
            // 生成字段、方法等字节码。
            this.emit(e, false, CollectionUtils.transform(constructors, MethodInfoTransformer.getInstance()), methods, actualMethods);
            // 结束代理类的构建。
            e.end_class();
        }
    }
}

Cglib底层是用ASM库来生成字节码的,这部分代码过多因此不再展开。上面代码段主要的流程就是用反射和ASM库构建出代理类所需的字节码,最后调用org.objectweb.asm.ClassWriter#toByteArray方法把字节码写入一个字节数组中。

当我们拿到了代理类的字节码,接下来就用java.lang.ClassLoader#defineClass方法载入字节码生成代理类的Class对象。

// 底层调用ClassLoader的defineClass方法。
ReflectUtils.defineClass(className, b, loader);

接下来就能通过Class对象拿到构造方法,最后通过构造方法生成代理类的实例,可以看到整体逻辑和JDK实现的动态代理是差不多的,只不过Cglib使用ASM来生成字节码。

下面我们看一下Cglib生成的代理类是怎样的,增加以下代码开启dump功能。

System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "./");

由于生成的类比较长,并且有多个类文件,这里只截取最关键的一段代码。

public class Proxied$$EnhancerByCGLIB$$14f006e6 extends Proxied implements Factory {

    public final void f() {
        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$f$0$0$Method, CGLIB$emptyArgs, CGLIB$f$0$0$Proxy);
        } else {
            super.f();
        }
    }
}

代码中的f()方法就是我们写在被代理类中的方法,可以看到这个方法覆盖了基类中的方法,它主要做的事就是调用我们事先传入的MethodInterceptor对象的intercept方法。