·

老生常谈系列之Aop--CGLIB动态代理的底层实现原理

老生常谈系列之Aop--CGLIB动态代理的底层实现原理

前言

上一篇老生常谈系列之Aop--JDK动态代理的底层实现原理简单讲解了JDK动态代理的实现,动态代理常用实现里面的双子星还有另一位--CGLIB,那么这一篇就会介绍CGLIB动态代理。这篇文章还是复用之前老生常谈系列之Aop--Spring Aop原理浅析文章的CGLIB部分的代码例子,CGLIB的使用是非常简单的,只需要自己实现一个MethodInterceptor,然后使用Enhancer#create()方法就可以创建一个动态代理处理,然后通过生成的代理类调用方法,即可实现Aop的效果。是不是很好奇为什么可以这么简单,接下来我们来分析CGLIB帮我们做了什么。

那么接下来文章主要分为两部分去解析

  • 动态代理的生成过程
  • 动态代理的调用过程

动态代理的生成

这一部分回答了动态代理是怎么生成的,CGLIB底层帮我们做了什么。可以看到创建代理对象离不开Enhancer类,那么这个类的作用是什么呢?摘取类上的注释如下:

  Generates dynamic subclasses to enable method interception. This
  class started as a substitute for the standard Dynamic Proxy support
  included with JDK 1.3, but one that allowed the proxies to extend a
  concrete base class, in addition to implementing interfaces. The dynamically
  generated subclasses override the non-final methods of the superclass and
  have hooks which callback to user-defined interceptor
  implementations.

翻译一下:通过生成动态子类让方法拦截生效。此类开始是作为 JDK 1.3 中包含的标准动态代理支持的替代品,但它允许代理扩展具体的基类,除了实现接口。动态生成的子类覆盖超类的非final方法,并具有回调到用户定义的拦截器实现的钩子。

简而言之,就是生成一个代理子类,调用方法的时候回调到自定义实现的拦截器里。

首先我们来看简单的示例代码

    @Test
    public void cglibProxyTest(){
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(CalculateServiceImpl.class);
        enhancer.setCallback(new MyMethodInterceptor());
        CalculateService calculateService  = (CalculateService) enhancer.create();
        calculateService.calculate();
    }

可以看到我们只需要设置superClasscallback后调用create()方法就可以生成一个想要的对象。
在开始分析代码之前,先来看一下执行的时序图。

图片来自https://www.ffutop.com/posts/2018-07-10-cglib-enhancer/

接下来就看一下create()发生了什么。

    /**
     * Generate a new class if necessary and uses the specified
     * callbacks (if any) to create a new object instance.
     * Uses the no-arg constructor of the superclass.
     * @return a new instance
     */
    public Object create() {
        classOnly = false;
        argumentTypes = null;
        return createHelper();
    }

可以看到这里利用KEY_FACTORY生成一个key,这个key封装了多个值,属于multi-valued keys的实现。我们来看一下KeyFactory的用法。

    private Object createHelper() {
        preValidate();
        Object key = KEY_FACTORY.newInstance((superclass != null) ? superclass.getName() : null,
                ReflectUtils.getNames(interfaces),
                filter == ALL_ZERO ? null : new WeakCacheKey<CallbackFilter>(filter),
                callbackTypes,
                useFactory,
                interceptDuringConstruction,
                serialVersionUID);
        this.currentKey = key;
        Object result = super.create(key);
        return result;
    }

KeyFactory是类库中重要的唯一标识生成器,用于CGLIB实现缓存时的key,比较底层的基础类。

摘取类上的注释如下:

Generates classes to handle multi-valued keys, for use in things such as Maps and Sets.
To generate a <code>KeyFactory</code>, you need to supply an interface which
describes the structure of the key. The interface should have a
single method named <code>newInstance</code>, which returns an
<code>Object</code>. The arguments array can be
<i>anything</i>--Objects, primitive values, or single or
multi-dimension arrays of either. For example:
<p><pre>
    private interface IntStringKey {
        public Object newInstance(int i, String s);
    }
 </pre><p>
 Once you have made a <code>KeyFactory</code>, you generate a new key by calling
 the <code>newInstance</code> method defined by your interface.
 <p><pre>
     IntStringKey factory = (IntStringKey)KeyFactory.create(IntStringKey.class);
     Object key1 = factory.newInstance(4, "Hello");
     Object key2 = factory.newInstance(4, "World");
</pre><p>

翻译一下:KeyFactory可以生成处理多值键的类,可以用于诸如 Maps 和 Sets 之类的东西。KeyFactory的使用也非常简单,只需要提供一个接口,定义一个newInstance()方法,调用(IntStringKey)KeyFactory.create(IntStringKey.class)就可以生成一个key类。

接下来通过super.create(key)调用父类的create(key)方法。

    protected Object create(Object key) {
        try {
            ClassLoader loader = getClassLoader();
            Map<ClassLoader, ClassLoaderData> cache = CACHE;
            // 先尝试通过缓存获取ClassLoaderData
            ClassLoaderData data = cache.get(loader);
            if (data == null) {
                synchronized (AbstractClassGenerator.class) {
                    cache = CACHE;
                    data = cache.get(loader);
                    if (data == null) {
                        Map<ClassLoader, ClassLoaderData> newCache = new WeakHashMap<ClassLoader, ClassLoaderData>(cache);
                        data = new ClassLoaderData(loader);
                        newCache.put(loader, data);
                        CACHE = newCache;
                    }
                }
            }
            this.key = key;
            // 这里真正生成了代理类
            Object obj = data.get(this, getUseCache());
            if (obj instanceof Class) {
                return firstInstance((Class) obj);
            }
            return nextInstance(obj);
        } 
        // 省略异常
    }

进入ClassLoaderData#get()方法

        public Object get(AbstractClassGenerator gen, boolean useCache) {
            if (!useCache) {
              return gen.generate(ClassLoaderData.this);
            } else {
              Object cachedValue = generatedClasses.get(gen);
              return gen.unwrapCachedValue(cachedValue);
            }
        }

跟进generatedClasses.get(gen)方法,这里第一次进来,前面都会为空,所以会进行节点创建createEntry()

    public V get(K key) {
        final KK cacheKey = keyMapper.apply(key);
        Object v = map.get(cacheKey);
        if (v != null && !(v instanceof FutureTask)) {
            return (V) v;
        }

        return createEntry(key, cacheKey, v);
    }

可以看到这里使用了FutureTask去异步执行创建,用于提升创建时候的性能。

    protected V createEntry(final K key, KK cacheKey, Object v) {
        FutureTask<V> task;
        boolean creator = false;
        if (v != null) {
            // Another thread is already loading an instance
            task = (FutureTask<V>) v;
        } else {
            // 创建一个FutureTask
            task = new FutureTask<V>(new Callable<V>() {
                public V call() throws Exception {
                    return loader.apply(key);
                }
            });
            // 校验这个任务是否已经存在
            Object prevTask = map.putIfAbsent(cacheKey, task);
            if (prevTask == null) {
                // creator does the load
                // 执行FutureTask
                creator = true;
                task.run();
            } else if (prevTask instanceof FutureTask) {
                task = (FutureTask<V>) prevTask;
            } else {
                return (V) prevTask;
            }
        }

        V result;
        try {
            // 走到这里说明是有正常执行的FutureTask,尝试获取FutureTask的结果
            result = task.get();
        } 
        // 省略部分异常
        if (creator) {
            map.put(cacheKey, result);
        }
        return result;
    }

上面的代码跟着注释看一下,重点在这里loader.apply(key),这个loadernew LoadingCache()的时候传入的。

task = new FutureTask<V>(new Callable<V>() {
                public V call() throws Exception {
                    return loader.apply(key);
                }
            });

loader的逻辑如下:

            Function<AbstractClassGenerator, Object> load =
                    new Function<AbstractClassGenerator, Object>() {
                        public Object apply(AbstractClassGenerator gen) {
                            // 这里生成代理class
                            Class klass = gen.generate(ClassLoaderData.this);
                            return gen.wrapCachedClass(klass);
                        }
                    };
            generatedClasses = new LoadingCache<AbstractClassGenerator, Object, Object>(GET_KEY, load);

跟进gen.generate(ClassLoaderData.this)方法

    protected Class generate(ClassLoaderData data) {
        Class gen;
        Object save = CURRENT.get();
        CURRENT.set(this);
        try {
            ClassLoader classLoader = data.getClassLoader();
            //省略部分逻辑和日志,重点在这里,这里会生成代理类的字节码
            byte[] b = strategy.generate(this);
            String className = ClassNameReader.getClassName(new ClassReader(b));
            ProtectionDomain protectionDomain = getProtectionDomain();
            synchronized (classLoader) { // just in case
                if (protectionDomain == null) {
                    gen = ReflectUtils.defineClass(className, b, classLoader);
                } else {
                    gen = ReflectUtils.defineClass(className, b, classLoader, protectionDomain);
                }
            }
            return gen;
        }
        // 省略异常
    }

默认的实现是DefaultGeneratorStrategy,可以看到这里先获取了一个DebuggingClassWriter,CGLIB封装ASM的处理类,用于生成class的byte流,通过GeneratorStrategy回调ClassGenerator.generateClass(DebuggingClassWriter),将自定义的class对象的byte处理回调给具体的CGLIB上层操作类,比如由具体的BeanCopier去控制字节码的生成。

    public byte[] generate(ClassGenerator cg) throws Exception {
        DebuggingClassWriter cw = getClassVisitor();
        transform(cg).generateClass(cw);
        return transform(cw.toByteArray());
    }

FastClassEmitter类的构造函数里,通过上面传入的DebuggingClassWriter封装了ASM的相关操作,用于动态生成代理类的字节码,这里不再深入ASM的原理,感兴趣可以看字节码操作框架ASM的实现原理

        public void generateClass(ClassVisitor v) throws Exception {
            new FastClassEmitter(v, getClassName(), type);
        }

最后再通过transform(cw.toByteArray())得到一个byte[]数组。好了,到这里已经可以得到一个代理的字节码了。接下来回到AbstractClassGenerator#create()方法里。

// obj为已经获取到的代理类,这里是一个Class对象
Object obj = data.get(this, getUseCache());
            if (obj instanceof Class) {
                return firstInstance((Class) obj);
            }
            return nextInstance(obj);

只需要把对象实例化返回,至此,已经获取了一个代理类。

        protected Object firstInstance(Class type) {
            return ReflectUtils.newInstance(type,
                                            new Class[]{ Class.class },
                                            new Object[]{ this.type });
        }

动态代理的调用

代码样例

这里搞个例子HelloServiceHelloMethodInterceptor对它增强。

public class HelloService {
    public void sayHello(){
        System.out.println("hello");
    }
}

public class HelloMethodInterceptor implements MethodInterceptor {
    @Override
    public Object intercept(Object object, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("before say hello...");
        return methodProxy.invokeSuper(object,objects);
    }
}

测试方法,把生成的代理类存下来。

public class HelloTest {

    @Test
    public void cglibProxyTest(){
        System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY,"C:\\my_study_project");
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(HelloService.class);
        enhancer.setCallback(new HelloMethodInterceptor());
        HelloService helloService  = (HelloService) enhancer.create();
        helloService.sayHello();
    }

}

那么上面的步骤生产了什么呢?我们来看一下生成的类有哪些。

1643026756445

HelloService$$EnhancerByCGLIB$$91933e33是生成的代理类,HelloService$$FastClassByCGLIB$$a685f36d是目标类的FastClassHelloService$$EnhancerByCGLIB$$91933e33$$FastClassByCGLIB$$33d595dd是代理类的FastClass

反编译后的代码

下面看一下每个类反编译后的代码

代理类

每个类的代码都很长,这里就不全部贴出来了,为了方便阅读,这里只留存sayHello()hashCode()方法做比对阐述。如果想查看全部的代码,自己把测试代码跑一下就能在相应的路径下找到这三个class文件。

package io.codegitz.service;

public class HelloService$$EnhancerByCGLIB$$91933e33 extends HelloService implements Factory {
    private boolean CGLIB$BOUND;
    public static Object CGLIB$FACTORY_DATA;
    private static final ThreadLocal CGLIB$THREAD_CALLBACKS;
    private static final Callback[] CGLIB$STATIC_CALLBACKS;
    private MethodInterceptor CGLIB$CALLBACK_0;
    private static Object CGLIB$CALLBACK_FILTER;
    
    private static final Method CGLIB$sayHello$0$Method;
    private static final MethodProxy CGLIB$sayHello$0$Proxy;

    private static final Method CGLIB$hashCode$3$Method;
    private static final MethodProxy CGLIB$hashCode$3$Proxy;


    // 初始化该类的所有方法
    static void CGLIB$STATICHOOK1() {
        CGLIB$THREAD_CALLBACKS = new ThreadLocal();
        CGLIB$emptyArgs = new Object[0];
        Class var0 = Class.forName("io.codegitz.service.HelloService$$EnhancerByCGLIB$$91933e33");
        Class var1;
        Method[] var10000 = ReflectUtils.findMethods(new String[]{"equals", "(Ljava/lang/Object;)Z", "toString", "()Ljava/lang/String;", "hashCode", "()I", "clone", "()Ljava/lang/Object;"}, (var1 = Class.forName("java.lang.Object")).getDeclaredMethods());
        
        CGLIB$hashCode$3$Method = var10000[2];
        CGLIB$hashCode$3$Proxy = MethodProxy.create(var1, var0, "()I", "hashCode", "CGLIB$hashCode$3");
        
        CGLIB$sayHello$0$Method = ReflectUtils.findMethods(new String[]{"sayHello", "()V"}, (var1 = Class.forName("io.codegitz.service.HelloService")).getDeclaredMethods())[0];
        CGLIB$sayHello$0$Proxy = MethodProxy.create(var1, var0, "()V", "sayHello", "CGLIB$sayHello$0");
    }

    // 调用目标类方法
    final void CGLIB$sayHello$0() {
        super.sayHello();
    }
    // 代理逻辑的方法
    public final void sayHello() {
        MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
        if (var10000 == null) {
            CGLIB$BIND_CALLBACKS(this);
            var10000 = this.CGLIB$CALLBACK_0;
        }
        if (var10000 != null) {
            var10000.intercept(this, CGLIB$sayHello$0$Method, CGLIB$emptyArgs, CGLIB$sayHello$0$Proxy);
        } else {
            super.sayHello();
        }
    }

    //hashCode方法也类似
    final int CGLIB$hashCode$3() {
        return super.hashCode();
    }

    public final int hashCode() {
        MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
        if (var10000 == null) {
            CGLIB$BIND_CALLBACKS(this);
            var10000 = this.CGLIB$CALLBACK_0;
        }
        if (var10000 != null) {
            Object var1 = var10000.intercept(this, CGLIB$hashCode$3$Method, CGLIB$emptyArgs, CGLIB$hashCode$3$Proxy);
            return var1 == null ? 0 : ((Number)var1).intValue();
        } else {
            return super.hashCode();
        }
    }

    // 生成MethodProxy,通过MethodProxy调用会生成fastClass,这是实现高性能调用的关键
    public static MethodProxy CGLIB$findMethodProxy(Signature var0) {
        String var10000 = var0.toString();
        switch(var10000.hashCode()) {
        case 1535311470:
            if (var10000.equals("sayHello()V")) {
                return CGLIB$sayHello$0$Proxy;
            }
            break;
        case 1984935277:
            if (var10000.equals("hashCode()I")) {
                return CGLIB$hashCode$3$Proxy;
            }
        }
        return null;
    }
    // 初始化方法
    static {
        CGLIB$STATICHOOK1();
    }
}

代理类fastClass

fastClass为所有的方法都建立了索引,在调用的时候通过传入索引来寻找方法,进而避免反射的性能开销,这是一种典型的空间换时间实现。

package io.codegitz.service;

import io.codegitz.service.HelloService..EnhancerByCGLIB..91933e33;
import java.lang.reflect.InvocationTargetException;
import net.sf.cglib.core.Signature;
import net.sf.cglib.proxy.Callback;
import net.sf.cglib.reflect.FastClass;

public class HelloService$$EnhancerByCGLIB$$91933e33$$FastClassByCGLIB$$33d595dd extends FastClass {
    public HelloService$$EnhancerByCGLIB$$91933e33$$FastClassByCGLIB$$33d595dd(Class var1) {
        super(var1);
    }

    // 通过方法签名获取方法索引
    public int getIndex(Signature var1) {
        String var10000 = var1.toString();
        switch(var10000.hashCode()) {
        case -1411842725:
            if (var10000.equals("CGLIB$hashCode$3()I")) {
                return 16;
            }
            break;
        case 291273791:
            if (var10000.equals("CGLIB$sayHello$0()V")) {
                return 14;
            }
            break;
        case 1535311470:
            if (var10000.equals("sayHello()V")) {
                return 7;
            }
            break;
        case 1984935277:
            if (var10000.equals("hashCode()I")) {
                return 2;
            }
        }
        return -1;
    }

    // 通过方法名获取索引
    public int getIndex(String var1, Class[] var2) {
        switch(var1.hashCode()) {
        case -2012993625:
            if (var1.equals("sayHello")) {
                switch(var2.length) {
                case 0:
                    return 7;
                }
            }
            break;
        case -1983192202:
            if (var1.equals("CGLIB$sayHello$0")) {
                switch(var2.length) {
                case 0:
                    return 14;
                }
            }
            break;
        case -29025555:
            if (var1.equals("CGLIB$hashCode$3")) {
                switch(var2.length) {
                case 0:
                    return 16;
                }
            }
            break;
        case 147696667:
            if (var1.equals("hashCode")) {
                switch(var2.length) {
                case 0:
                    return 2;
                }
            }
            break;
        }
        return -1;
    }

    public int getIndex(Class[] var1) {
        switch(var1.length) {
        case 0:
            return 0;
        default:
            return -1;
        }
    }

    // 通过传入方法的索引var1获取方法执行
    public Object invoke(int var1, Object var2, Object[] var3) throws InvocationTargetException {
        91933e33 var10000 = (91933e33)var2;
        int var10001 = var1;

        try {
            switch(var10001) {
            case 2:
                return new Integer(var10000.hashCode());
            case 7:
                var10000.sayHello();
                return null;
            case 14:
                var10000.CGLIB$sayHello$0();
                return null;
            case 16:
                return new Integer(var10000.CGLIB$hashCode$3());
            }
        } catch (Throwable var4) {
            throw new InvocationTargetException(var4);
        }

        throw new IllegalArgumentException("Cannot find matching method/constructor");
    }

    public Object newInstance(int var1, Object[] var2) throws InvocationTargetException {
        91933e33 var10000 = new 91933e33;
        91933e33 var10001 = var10000;
        int var10002 = var1;

        try {
            switch(var10002) {
            case 0:
                var10001.<init>();
                return var10000;
            }
        } catch (Throwable var3) {
            throw new InvocationTargetException(var3);
        }

        throw new IllegalArgumentException("Cannot find matching method/constructor");
    }

    public int getMaxIndex() {
        return 20;
    }
}

目标类fastClass

CGLIB不仅对代理类生成fastClass,会对原有的目标类也会生成一个fastClass,原理是类似的,都是通过建立方法的索引,通过传入索引寻找到方法,执行方法,避免了反射获取方法的性能开销。

package io.codegitz.service;

import java.lang.reflect.InvocationTargetException;
import net.sf.cglib.core.Signature;
import net.sf.cglib.reflect.FastClass;

public class HelloService$$FastClassByCGLIB$$a685f36d extends FastClass {
    public HelloService$$FastClassByCGLIB$$a685f36d(Class var1) {
        super(var1);
    }
    // 通过方法签名获取索引
    public int getIndex(Signature var1) {
        String var10000 = var1.toString();
        switch(var10000.hashCode()) {
        case 1535311470:
            if (var10000.equals("sayHello()V")) {
                return 0;
            }
            break;
        case 1984935277:
            if (var10000.equals("hashCode()I")) {
                return 3;
            }
        }
        return -1;
    }

    // 通过方法名获取方法索引
    public int getIndex(String var1, Class[] var2) {
        switch(var1.hashCode()) {
        case -2012993625:
            if (var1.equals("sayHello")) {
                switch(var2.length) {
                case 0:
                    return 0;
                }
            }
            break;
        case 147696667:
            if (var1.equals("hashCode")) {
                switch(var2.length) {
                case 0:
                    return 3;
                }
            }
        }
        return -1;
    }

    public int getIndex(Class[] var1) {
        switch(var1.length) {
        case 0:
            return 0;
        default:
            return -1;
        }
    }

    // 根据传入的var1获取对应的方法执行
    public Object invoke(int var1, Object var2, Object[] var3) throws InvocationTargetException {
        HelloService var10000 = (HelloService)var2;
        int var10001 = var1;

        try {
            switch(var10001) {
            case 0:
                var10000.sayHello();
                return null;
            case 3:
                return new Integer(var10000.hashCode());
            }
        } catch (Throwable var4) {
            throw new InvocationTargetException(var4);
        }

        throw new IllegalArgumentException("Cannot find matching method/constructor");
    }

    public Object newInstance(int var1, Object[] var2) throws InvocationTargetException {
        HelloService var10000 = new HelloService;
        HelloService var10001 = var10000;
        int var10002 = var1;

        try {
            switch(var10002) {
            case 0:
                var10001.<init>();
                return var10000;
            }
        } catch (Throwable var3) {
            throw new InvocationTargetException(var3);
        }

        throw new IllegalArgumentException("Cannot find matching method/constructor");
    }

    public int getMaxIndex() {
        return 3;
    }
}

调用过程分析

这些码看起来是不是很乱?完全不知道从哪里开始执行?

在开始代码分析之前,先看一下执行流程图,步骤还是比较简单明了

1643092242984

1643032125938

接着下一步,这里就是进入动态代理类的逻辑,可以看HelloService$$EnhancerByCGLIB$$91933e33#sayHello()方法。

    public final void sayHello() {
        // 获取拦截器,这里就是HelloMethodInterceptor
        MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
        if (var10000 == null) {
            CGLIB$BIND_CALLBACKS(this);
            var10000 = this.CGLIB$CALLBACK_0;
        }

        // 不为空,则执行拦截器
        if (var10000 != null) {
            // 注意这里传入的参数,这里传入了一个method和一个MethodProxy,这里就会进入到自定义的HelloMethodInterceptor里面的逻辑
            var10000.intercept(this, CGLIB$sayHello$0$Method, CGLIB$emptyArgs, CGLIB$sayHello$0$Proxy);
        } else {
            super.sayHello();
        }
    }

这里是通过methodProxy.invokeSuper(object,objects),调用invokeSuper()方法,注意这里methodProxy还有个invoke()方法可以调用,那么这两者有什么区别呢?显而易见invokeSuper()就是调用父类的方法,而invoke()是调用代理经过拦截器的方法,如果调用invoke()那么每次都会走到拦截器,会造成死循环。

1643032549367

跟进methodProxy.invokeSuper()方法,根据注释可以看到,这里就是调用了原有的没有经过代理的方法。

    /**
     * Invoke the original (super) method on the specified object.
     * @param obj the enhanced object, must be the object passed as the first
     * argument to the MethodInterceptor
     * @param args the arguments passed to the intercepted method; you may substitute a different
     * argument array as long as the types are compatible
     * @see MethodInterceptor#intercept
     * @throws Throwable the bare exceptions thrown by the called method are passed through
     * without wrapping in an <code>InvocationTargetException</code>
     */
    public Object invokeSuper(Object obj, Object[] args) throws Throwable {
        try {
            init();
            FastClassInfo fci = fastClassInfo;
            return fci.f2.invoke(fci.i2, obj, args);
        } catch (InvocationTargetException e) {
            throw e.getTargetException();
        }
    }

可以看到,这里的调用跟反射调用是有区别的。反射调用一般是直接把方法传入,然后直接invoke(),而这里会先进行init(),初始化一个FastClassInfo,再通过fci.f2.invoke(fci.i2, obj, args)去调用方法,这里就是前面说的实现高性能调用的关键,这里会为代理类方法和实现类的FastClass,然后在调用时通过传入方法的下标索引直接获取方法执行,从而实现了空间换时间操作。

来看init()方法,这个方法是用来初始化fastClassInfo类的,详细的初始化过程就不解析了,这里只是最终生成了什么就好。

    private void init()
    {
        /* 
         * 使用 volatile 不变量允许我们以原子方式初始化 FastClass 和方法索引对
         * Using a volatile invariant allows us to initialize the FastClass and
         * method index pairs atomically.
         * 
         * 双重检查锁定在 Java 5 中使用 volatile 是安全的。在 1.5 之前,此代码可能允许多次实例化 fastClassInfo,这似乎是良性的。
         * Double-checked locking is safe with volatile in Java 5.  Before 1.5 this 
         * code could allow fastClassInfo to be instantiated more than once, which
         * appears to be benign.
         */
        if (fastClassInfo == null)
        {
            synchronized (initLock)
            {
                if (fastClassInfo == null)
                {
                    CreateInfo ci = createInfo;

                    FastClassInfo fci = new FastClassInfo();
                    // 生成目标类fastClass
                    fci.f1 = helper(ci, ci.c1);
                    // 生成代理类fastClass
                    fci.f2 = helper(ci, ci.c2);
                    // 生成目标类index
                    fci.i1 = fci.f1.getIndex(sig1);
                    // 生成代理类index
                    fci.i2 = fci.f2.getIndex(sig2);
                    fastClassInfo = fci;
                    createInfo = null;
                }
            }
        }
    }

以下是初始化时各个属性的赋值

1643089308951

初始化完成后,就可以回到fci.f2.invoke(fci.i2, obj, args)调用上了,可以看到fci.f2的类型是HelloService$$EnhancerByCGLIB$$91933e33$$FastClassByCGLIB$$33d595dd,也就是上面贴出来的代理类的fastClass,来看一下这个类的invoke()方法

1643089612964查看反编译的invoke()方法代码

    public Object invoke(int var1, Object var2, Object[] var3) throws InvocationTargetException {
        91933e33 var10000 = (91933e33)var2;
        int var10001 = var1;

        try {
            switch(var10001) {
            case 2:
                return new Integer(var10000.hashCode());
            case 7:
                var10000.sayHello();
                return null;
            case 16:
                var10000.CGLIB$sayHello$0();
                return null;
            case 17:
                return new Integer(var10000.CGLIB$hashCode$3());
            }
        } catch (Throwable var4) {
            throw new InvocationTargetException(var4);
        }

        throw new IllegalArgumentException("Cannot find matching method/constructor");
    }

这里switch会匹配到16,然后执行var10000.CGLIB$sayHello$0(),这个var10000的类型是

1643090468444

找到HelloService$$EnhancerByCGLIB$$91933e33#CGLIB$sayHello$0()方法,可以看到,这里直接调用了HelloService#sayHello()方法。同样,methodProxy#invoke()方法逻辑也是类似,注意区分调用的时候不要死循环就是了。

    final void CGLIB$sayHello$0() {
        super.sayHello();
    }

到这里,可以看到CGLIB生成的代理方法调用时,先经过调用拦截器,然后再调用到目标方法,其中methodProxy调用目标方法时,会生成fastClassfastClass中存有代理类和目标类的所有方法以及匹配的下标,通过传入的下标就可以寻找到对应的方法,这里的方法调用只需要第一次进来初始化fastClass,后续可以直接调用,从而提高执行的性能,这也是CGLIB执行效率比JDK动态代理高的关键。这里空间换时间的思想值得我们借鉴,适当地消耗内存来提升执行效率是完全值得的。

总结

回顾一下这篇文章,前半部分通过一个例子,大概讲解了CGLIB生成一个代理类的步骤,但是具体集成ASM部分的字节码操作被略过,水平有效,不敢造次。挖了个坑,以后有能力再填。后半部分结合反编译的class文件,解释了调用的过程,这部分很简单,自己调试一下应该很快就能理清。

如果有人看到这里,那在这里老话重提。与君共勉,路漫漫其修远兮,吾将上下而求索。

posted @ 2022-01-25 15:12  Codegitz  阅读(291)  评论(0编辑  收藏  举报