CGLIB动态代理源码分析

Wesley13
• 阅读 696

CGLIB动态代理样例

由于CGLIB是JDK之外的东西,因此在使用CGLIB的时候需要引入CGLIB的包(我这里是gradle项目):

dependencies { implementation('cglib:cglib:3.3.0') }

要被代理的类:

package com.example.demo.proxy.cglib;

public class Hello {
    public void sayHello(String name) {
        System.out.println("Hello " + name);
    }
}

一个自定义的方法拦截器,该拦截器实现了net.sf.cglib.proxy.MethodInterceptor接口:

package com.example.demo.proxy.cglib;

import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

public class MyMethodInterceptor implements MethodInterceptor {
    @Override
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
        System.out.println(">>>> Before method invocation");
        Object object = proxy.invokeSuper(obj, args);
        System.out.println(">>>> After method invocation");
        return object;
    }
}

主测试类CglibProxyDemo.java:

package com.example.demo.proxy.cglib;

import net.sf.cglib.core.DebuggingClassWriter;
import net.sf.cglib.proxy.Enhancer;

/**
 * Cglib proxy demo.
 * Main implementation steps:
 * 1. Implement the net.sf.cglib.proxy.MethodInterceptor interface
 * 2. Create Enhancer object(which is used to create proxy object), set target class and callback object.
 * 3. Create proxy object by invoke enhancer.create()
 * 4. Call method on proxy object
 */
public class CglibProxyDemo {
    public static void main(String[] args) {
        //Generate proxy class under given path
        System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "out");

        //2. Create Enhancer object, which is used to create proxy object.
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(Hello.class); //Set target class
        enhancer.setCallback(new MyMethodInterceptor()); //Set callback object

        //3. Create proxy by invoke enhancer.create().
        Hello helloProxy = (Hello) enhancer.create();

        //4. Call method on proxy object.
        helloProxy.sayHello("Doris");
    }
}

执行结果:

CGLIB动态代理源码分析

可以看到,原来的Hello.sayHello()方法已经被代理了,加入了调用的前置处理和后置处理。

源码分析

先看看主测试类CglibProxyDemo.java,里面创建了一个enhancer,并且给它设置了superClass和callback两个属性,然后用这个enhancer创建了一个代理对象helloProxy,最后调用了代理对象的sayHello()方法。

创建代理对象 Hello helloProxy = (Hello) enhancer.create();

1.获取Key

代理对象helloProxy通过以下语句创建:

Hello helloProxy = (Hello) enhancer.create();

在Enhancer中:

/**
 * 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();
}

在createHelper()中,创建了一个唯一的key,用于在缓存中存取代理类的Class实例,并且立即调用父类AbstractClassGenerator.create(Object key)方法创建代理类的实例:

private Object createHelper() {
    preValidate();
    //创建key,用于在缓存中存取代理类实例
    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;
    //调用父类AbstractClassGenerator.create()创建代理类实例
    Object result = super.create(key);
    return result;
}

在create()中,会调用内部类ClassLoaderDataget(AbstractClassGenerator gen, boolean useCache)方法获取代理类的Class实例:

protected Object create(Object key) {
    try {
        ClassLoader loader = getClassLoader();
        Map<ClassLoader, AbstractClassGenerator.ClassLoaderData> cache = CACHE;
        AbstractClassGenerator.ClassLoaderData data = cache.get(loader);
        if (data == null) {
            synchronized (AbstractClassGenerator.class) {
                cache = CACHE;
                //加锁后再试一次,如果还没取到,就创建缓存
                data = cache.get(loader);
                if (data == null) {
                    Map<ClassLoader, AbstractClassGenerator.ClassLoaderData> newCache = new WeakHashMap<ClassLoader, AbstractClassGenerator.ClassLoaderData>(cache);
                    data = new AbstractClassGenerator.ClassLoaderData(loader);
                    newCache.put(loader, data);
                    CACHE = newCache;
                }
            }
        }
        this.key = key;
        //从ClassLoaderData中获取代理类的Class实例
        Object obj = data.get(this, getUseCache());
        if (obj instanceof Class) {
            //获取代理类的实例
            return firstInstance((Class) obj);
        }
        return nextInstance(obj);
    } catch (RuntimeException e) {
        throw e;
    } catch (Error e) {
        throw e;
    } catch (Exception e) {
        throw new CodeGenerationException(e);
    }
}

2.通过Key从缓存中获取Class

在ClassLoaderData中,有个字段generatedClasses,这个对象存放着当前类加载器加载的代理类的Class类实例,下面的方法本质,就是从这个generatedClasses里面匹配

//只要代理类的classLoader存在,这些代理类就是可以重用的
//通过generatedClasses缓存是获取代理类的唯一方法
private final LoadingCache<AbstractClassGenerator, Object, Object> generatedClasses;

// ...

public Object get(AbstractClassGenerator gen, boolean useCache) {
    //默认是使用缓存的,可以通过以下属性设置不使用缓存
    //System.setProperty("cglib.useCache", "false")
    if (!useCache) {
        return gen.generate(AbstractClassGenerator.ClassLoaderData.this);
    } else {
        //从generatedClasses中获取Class对象
        Object cachedValue = generatedClasses.get(gen);
        return gen.unwrapCachedValue(cachedValue);
    }
}

再来看看LoadingCache这个类,需要重点理解这三个字段:

//K:AbstractClassGenerator 这里指Enhancer类
//KK:Object 这里指前面生成key的类
//V:Object 这里指代理类的Class类
public class LoadingCache<K, KK, V> {
    //通过key可以拿到代理类的Class实例
    protected final ConcurrentMap<KK, Object> map;
    //通过loader.apply(Enhancer实例)可以获得代理类的Class实例
    protected final Function<K, V> loader;
    //通过keyMapper.apply(Enhancer实例)可以获得key
    protected final Function<K, KK> keyMapper;

    //·······
}

在get方法中,通过key生成的cachKey去缓存中查找,如果没找到,则创建Class实例,并放入缓存map中:

public V get(K key) {
    //通过key生成cacheKey
    final KK cacheKey = keyMapper.apply(key);
    //通过cacheKey查找缓存
    Object v = map.get(cacheKey);
    if (v != null && !(v instanceof FutureTask)) {
        return (V) v;
    }
    //如果没找到,就创建Class实例,并放入缓存
    return createEntry(key, cacheKey, v);
}

3.生成代理类Class

//LoadingCache.createEntry()
//省略了无关代码
protected V createEntry(final K key, KK cacheKey, Object v) {
    //创建Class实例
    V result = loader.apply(key);
    //放入缓存中
    map.put(cacheKey, result);
    return result;
}

loader是一个Function,是创建LoadingCache的时候通过构造器传入的,loader是在AbstractClassGenerator的内部类ClassLoaderData中创建的:

//AbstractClassGenerator$ClassLoaderData的构造函数
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);

4.创建代理对象

创建了代理类的Class对象后,通过AbstractClassGenerator.firstInstance(Class type)来创建代理类的实例,该方法是一个abstract方法,实现在Enhancer中:

//Enhancer
protected Object firstInstance(Class type) throws Exception {
    if (classOnly) {
        return type;
    } else {
        //会执行到这里
        return createUsingReflection(type);
    }
}

/**
 * Instantiates a proxy instance and assigns callback values.
 * Implementation detail: java.lang.reflect instances are not cached, so this method should not
 * be used on a hot path.
 * This method is used when {@link #setUseCache(boolean)} is set to {@code false}.
 *
 * @param type class to instantiate
 * @return newly created instance
 */
private Object createUsingReflection(Class type) {
    setThreadCallbacks(type, callbacks);
    try{
        if (argumentTypes != null) {
            return ReflectUtils.newInstance(type, argumentTypes, arguments);
        } else {
            return ReflectUtils.newInstance(type);
        }
    } finally {
        // clear thread callbacks to allow them to be gc'd
        setThreadCallbacks(type, null);
    }
}

最后就是通过反射创建了代理类的实例。

调用代理对象的方法 helloProxy.sayHello("Doris");

1.代理类的源码分析

从测试结果可以看到,对于helloProxy.sayHello("Doris");的调用,最终调用到了MyInterceptor.intercept()方法上,为什么呢?先看下debug模式下的helloProxy的类型:

CGLIB动态代理源码分析

可以看到,helloProxy对象的类型是“Hello$$EnhancerByCGLIB$$190a8bdd”,这是一个CGLIB生成的用于代理Hello的代理类,并且其CGLIB$CALLBACK_0属性就是我们通过enhancer.setCallback()设置的MyMethodInterceptor。

为了便于分析,我们通过第一句保留了CGLIB生成的动态代理的文件在项目根目录的out文件夹下:

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

CGLIB动态代理源码分析

在IDEA中打开打开这个生成的代理类:

package com.example.demo.proxy.cglib;

import java.lang.reflect.Method;
import net.sf.cglib.core.ReflectUtils;
import net.sf.cglib.core.Signature;
import net.sf.cglib.proxy.Callback;
import net.sf.cglib.proxy.Factory;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

//可以看到这个代理类是Hello的子类,并且实现了Factory接口,该接口主要用于实例化对象和设置回调函数。
//生成的类名的规则:被代理ClassName + "$$" + ClassGeneratorName + "ByCGLIB" + "$$" + key的hashCode
public class Hello$$EnhancerByCGLIB$$190a8bdd extends Hello 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;

    //这里有很多属性,基本上一个Method对应一个MethodProxy
    private static final Method CGLIB$sayHello$0$Method;//被代理的sayHello()方法
    private static final MethodProxy CGLIB$sayHello$0$Proxy;//代理的sayHello()方法
    private static final Object[] CGLIB$emptyArgs;
    private static final Method CGLIB$equals$1$Method;
    private static final MethodProxy CGLIB$equals$1$Proxy;
    private static final Method CGLIB$toString$2$Method;
    private static final MethodProxy CGLIB$toString$2$Proxy;
    private static final Method CGLIB$hashCode$3$Method;
    private static final MethodProxy CGLIB$hashCode$3$Proxy;
    private static final Method CGLIB$clone$4$Method;
    private static final MethodProxy CGLIB$clone$4$Proxy;

    // 静态代码块,主要是通过【反射】获取了以下方法的字节码:
    // Object.equals()
    // Object.toString()
    // Object.hashCode()
    // Object.clone()
    // Hello.sayHello()
    // 并为这些方法创建对应的MethodProxy
    static void CGLIB$STATICHOOK1() {
        CGLIB$THREAD_CALLBACKS = new ThreadLocal();
        CGLIB$emptyArgs = new Object[0];
        //代理类Class对象
        Class var0 = Class.forName("com.example.demo.proxy.cglib.Hello$$EnhancerByCGLIB$$190a8bdd");
        //被代理类Class对象
        Class var1;
        //被代理类var1在这一行被赋值为java.lang.Object
        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$equals$1$Method = var10000[0];
        CGLIB$equals$1$Proxy = MethodProxy.create(var1, var0, "(Ljava/lang/Object;)Z", "equals", "CGLIB$equals$1");
        CGLIB$toString$2$Method = var10000[1];
        CGLIB$toString$2$Proxy = MethodProxy.create(var1, var0, "()Ljava/lang/String;", "toString", "CGLIB$toString$2");
        CGLIB$hashCode$3$Method = var10000[2];
        CGLIB$hashCode$3$Proxy = MethodProxy.create(var1, var0, "()I", "hashCode", "CGLIB$hashCode$3");
        CGLIB$clone$4$Method = var10000[3];
        CGLIB$clone$4$Proxy = MethodProxy.create(var1, var0, "()Ljava/lang/Object;", "clone", "CGLIB$clone$4");
        //被代理类var1在这一行被赋值为com.example.demo.proxy.cglib.Hello
        CGLIB$sayHello$0$Method = ReflectUtils.findMethods(new String[]{"sayHello", "(Ljava/lang/String;)V"}, (var1 = Class.forName("com.example.demo.proxy.cglib.Hello")).getDeclaredMethods())[0];
        //这里创建了sayHello方法的代理
        CGLIB$sayHello$0$Proxy = MethodProxy.create(var1, var0, "(Ljava/lang/String;)V", "sayHello", "CGLIB$sayHello$0");
    }

    //这个方法就是调用目标类的sayHello()方法
    final void CGLIB$sayHello$0(String var1) {
        super.sayHello(var1);
    }

    //这个方法就是sayHello()方法在代理对象中的实现,即在我们样例中helloProxy.sayHello()调用的方法
    public final void sayHello(String var1) {
        MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
        if (var10000 == null) {
            CGLIB$BIND_CALLBACKS(this);
            var10000 = this.CGLIB$CALLBACK_0;
        }

        //var10000就是样例中enhancer.setCallback(new MyMethodInterceptor());设置的方法拦截器
        if (var10000 != null) {
            //如果方法拦截器存在,就调用它的interceptor方法。就会调用MyMethodInterceptor.intercept()方法
            var10000.intercept(this, CGLIB$sayHello$0$Method, new Object[]{var1}, CGLIB$sayHello$0$Proxy);
        } else {
            //如果方法拦截器不存在,就只执行目标类的sayHello()方法
            super.sayHello(var1);
        }
    }

    //...
    //省略了equals, toString, hashCode, clone等方法的实现,逻辑都是类似的:
    //如果方法拦截器存在,就调用拦截器的intercept方法,否则直接调用父类的方法
    //...

    public static MethodProxy CGLIB$findMethodProxy(Signature var0) {
        String var10000 = var0.toString();
        switch(var10000.hashCode()) {
            case -508378822:
                if (var10000.equals("clone()Ljava/lang/Object;")) {
                    return CGLIB$clone$4$Proxy;
                }
                break;
            case 771401912:
                if (var10000.equals("sayHello(Ljava/lang/String;)V")) {
                    return CGLIB$sayHello$0$Proxy;
                }
                break;
            case 1826985398:
                if (var10000.equals("equals(Ljava/lang/Object;)Z")) {
                    return CGLIB$equals$1$Proxy;
                }
                break;
            case 1913648695:
                if (var10000.equals("toString()Ljava/lang/String;")) {
                    return CGLIB$toString$2$Proxy;
                }
                break;
            case 1984935277:
                if (var10000.equals("hashCode()I")) {
                    return CGLIB$hashCode$3$Proxy;
                }
        }

        return null;
    }

    //无参构造函数
    public Hello$$EnhancerByCGLIB$$190a8bdd() {
        CGLIB$BIND_CALLBACKS(this);
    }

    public static void CGLIB$SET_THREAD_CALLBACKS(Callback[] var0) {
        CGLIB$THREAD_CALLBACKS.set(var0);
    }

    public static void CGLIB$SET_STATIC_CALLBACKS(Callback[] var0) {
        CGLIB$STATIC_CALLBACKS = var0;
    }

    private static final void CGLIB$BIND_CALLBACKS(Object var0) {
        Hello$$EnhancerByCGLIB$$190a8bdd var1 = (Hello$$EnhancerByCGLIB$$190a8bdd)var0;
        if (!var1.CGLIB$BOUND) {
            var1.CGLIB$BOUND = true;
            Object var10000 = CGLIB$THREAD_CALLBACKS.get();
            if (var10000 == null) {
                var10000 = CGLIB$STATIC_CALLBACKS;
                if (var10000 == null) {
                    return;
                }
            }

            var1.CGLIB$CALLBACK_0 = (MethodInterceptor)((Callback[])var10000)[0];
        }

    }

    //...
    //省略了实现的Factory接口的方法
    //...

    //调用静态代码块,完成Method和MethodProxy的初始化
    static {
        CGLIB$STATICHOOK1();
    }
}

可以看到,当在代理对象上调用sayHello()方法时,会先检查这个代理对象是否有MethodInterceptor,如果有,则调用其intercept方法,没有则直接调用目标对象的sayHello()方法。这里就进入到了MyMethodInterceptor.intercept()方法,打印了这句话:

>>>> Before method invocation

2. MethodProxy.invokeSuper()

这里的MethodProxy是在代理类的静态块CGLIB$STATICHOOK1中通过创建的:

//Hello$$EnhancerByCGLIB$$190a8bdd
CGLIB$sayHello$0$Proxy = MethodProxy.create(var1, var0, "(Ljava/lang/String;)V", "sayHello", "CGLIB$sayHello$0");

//MethodProxy
public static MethodProxy create(Class c1, Class c2, String desc, String name1, String name2) {
    MethodProxy proxy = new MethodProxy();
    proxy.sig1 = new Signature(name1, desc);
    proxy.sig2 = new Signature(name2, desc);
    //创建了createInfo属性
    proxy.createInfo = new MethodProxy.CreateInfo(c1, c2);
    return proxy;
}

这里创建了proxy对象的createInfo属性,接下来会在invokeSuper()方法中调用init()方法的时候,用该属性来创建FastClass类

public Object invokeSuper(Object obj, Object[] args) throws Throwable {
    try {
        //初始化,创建了两个FastClass类对象,并根据原来的方法签名得到方法索引
        init();
        //这个对象持有两个FastClass类对象和方法的索引,见下方FastClassInfo类
        MethodProxy.FastClassInfo fci = fastClassInfo;
        //f2是代理对象的FastClass,这里是调用代理对象上索引为i2的方法
        return fci.f2.invoke(fci.i2, obj, args);
    } catch (InvocationTargetException e) {
        throw e.getTargetException();
    }
}

private void init() {
    if (fastClassInfo == null) {
        synchronized (initLock) {
            if (fastClassInfo == null) {
                //用createInfo属性来创建FastClassInfo
                MethodProxy.CreateInfo ci = createInfo;
                MethodProxy.FastClassInfo fci = new MethodProxy.FastClassInfo();
                
                //helper方法用ASM框架生成了两个FastClass类
                fci.f1 = helper(ci, ci.c1);//目标类的FastClass
                fci.f2 = helper(ci, ci.c2);//代理类的FastClass

                //分别从FastClass中获取指定签名的方法
                fci.i1 = fci.f1.getIndex(sig1);//在目标类的FastClass中获取方法索引
                fci.i2 = fci.f2.getIndex(sig2);//在代理类的FastClass中获取方法索引
                
                //将fci赋值给全局变量fastClassInfo
                fastClassInfo = fci;
                createInfo = null;
            }
        }
    }
}

private static class FastClassInfo {
    //目标类的FastClass类
    FastClass f1;
    //代理类的FastClass类
    FastClass f2;
    //目标类FastClass中的方法索引
    int i1;
    //代理类FastClass中的方法索引
    int i2;
}

这里主要是通过MethodProxy.init()方法为目标类和代理类分别创建了FastClass,然后初始化了一个FastClassInfo对象(该对象持有两个FastClass以及FastClass中对于该方法的索引),最后在代理对象上调用了invoke方法。

3.FastClass类的代码分析

来看看代理类的FastClass(就是CGLIB生成的文件名最长的类),它是net.sf.cglib.reflect.FastClass的子类,主要用于给指定的类(这里是代理类)建立方法索引,避免每次使用反射去调用方法。该类里面主要是通过方法签名(Signature)获取方法索引(index)的方法,以及通过方法索引(index)调用方法的方法。

package com.example.demo.proxy.cglib;

import com.example.demo.proxy.cglib.Hello..EnhancerByCGLIB..190a8bdd;
import java.lang.reflect.InvocationTargetException;
import net.sf.cglib.core.Signature;
import net.sf.cglib.reflect.FastClass;

public class Hello$$EnhancerByCGLIB$$190a8bdd$$FastClassByCGLIB$$cbc4a17e extends FastClass {
    public Hello$$EnhancerByCGLIB$$190a8bdd$$FastClassByCGLIB$$cbc4a17e(Class var1) {
        super(var1);
    }

    //通过方法签名获取方法的索引,该索引将用于快速调用方法(下面invoke方法中的case)
    public int getIndex(Signature var1) {
        String var10000 = var1.toString();
        switch(var10000.hashCode()) {
            case 771401912:
                if (var10000.equals("sayHello(Ljava/lang/String;)V")) {
                    return 14;
                }
                break;
            //...省略其他的case
        }
        return -1;
    }

    //通过方法名和参数类型获取方法的索引。比如var1="sayHello", var2=[java.lang.String]
    /**
     * Return the index of the matching method. The index may be used
     * later to invoke the method with less overhead. If more than one
     * method matches (i.e. they differ by return type only), one is
     * chosen arbitrarily.
     * @see #invoke(int, Object, Object[])
     * @param name the method name
     * @param parameterTypes the parameter array
     * @return the index, or <code>-1</code> if none is found.
     */
    public int getIndex(String var1, Class[] var2) {
        switch(var1.hashCode()) {
            case -2012993625:
                if (var1.equals("sayHello")) {
                    switch(var2.length) {
                        case 1:
                            if (var2[0].getName().equals("java.lang.String")) {
                                return 14;
                            }
                    }
                }
                break;
            //...省略其他的case
        }
        return -1;
    }

    //通过参数类型获取构造器的索引,该索引用于稍后创建实例(下面newInstance方法中的case)
    /**
     * Return the index of the matching constructor. The index may be used
     * later to create a new instance with less overhead.
     * @see #newInstance(int, Object[])
     * @param parameterTypes the parameter array
     * @return the constructor index, or <code>-1</code> if none is found.
     */
    public int getIndex(Class[] var1) {
        switch(var1.length) {
            //只有一个默认的无参构造器,因此只有一个case 0
            case 0:
                return 0;
            default:
                return -1;
        }
    }

    //调用方法(注释来自FastClass类)
    /**
     * Invoke the method with the specified index.
     * @see getIndex(name, Class[])
     * @param index the method index
     * @param obj the object the underlying method is invoked from
     * @param args the arguments used for the method call
     * @throws java.lang.reflect.InvocationTargetException if the underlying method throws an exception
     */
    public Object invoke(int var1, Object var2, Object[] var3) throws InvocationTargetException {
        190a8bdd var10000 = (190a8bdd)var2;
        int var10001 = var1;

        try {
            switch(var10001) {
                //这里的case的情况都由getIndex(Signature var1)方法
                //或getIndex(String var1, Class[] var2)方法返回
                case 14:
                    var10000.sayHello((String)var3[0]);
                    return null;
                //...省略其他的case
            }
        } catch (Throwable var4) {
            throw new InvocationTargetException(var4);
        }

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

    //通过构造器实例化对象(注释来自FastClass类)
    /**
     * Create a new instance using the specified constructor index and arguments.
     * @see getIndex(Class[])
     * @param index the constructor index
     * @param args the arguments passed to the constructor
     * @throws java.lang.reflect.InvocationTargetException if the constructor throws an exception
     */
    public Object newInstance(int var1, Object[] var2) throws InvocationTargetException {
        190a8bdd var10000 = new 190a8bdd;
        190a8bdd var10001 = var10000;
        int var10002 = var1;

        try {
            switch(var10002) {
                case 0:
                    //构造器是0个参数,表示通过无参构造器创建对象
                    var10001.<init>();
                    return var10000;
            }
        } catch (Throwable var3) {
            throw new InvocationTargetException(var3);
        }

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

    /**
     * Returns the maximum method index for this class.
     */
    public int getMaxIndex() {
        return 20;
    }
}

可以看到,对于proxy.invokeSuper()的调用,实际上调用了fci.f2.invoke(fci.i2, obj, args)。而fci.i2 = fci.f2.getIndex(sig2); 注意这里的sig2是指CGLIB$sayHello$0()这个方法,即代理对象中用于调用目标对象sayHello()的方法

所以整个调用流程为:

1.通过sayHello()的方法签名,在代理类的FastClass中找到**CGLIB$sayHello$0()**方法的索引。

2.调用fci.f2.invoke()方法,因此直接调用代理对象的**CGLIB$sayHello$0()**方法,于是间接调用到了Hello.sayHello()方法,输出了下面这句:

Hello Doris

最后继续在MyMethodInterceptor中输出了

>>>> After method invocation

【全文完】

=========================分隔线=====================================

参考:https://zhuanlan.zhihu.com/p/106069224

=========================分隔线=====================================

源码:https://github.com/wanxiaolong/JavaProxyDemo

点赞
收藏
评论区
推荐文章
blmius blmius
3年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
待兔 待兔
3个月前
手写Java HashMap源码
HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22
Jacquelyn38 Jacquelyn38
3年前
2020年前端实用代码段,为你的工作保驾护航
有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )
Wesley13 Wesley13
3年前
jdk动态代理和cglib动态代理底层实现原理详细解析(cglib动态代理篇)
  代理模式是一种很常见的模式,本文主要分析cglib动态代理的过程1\.举例使用cglib代理需要引入两个包,maven的话包引入如下<!https://mvnrepository.com/artifact/cglib/cglib<dependency
Wesley13 Wesley13
3年前
JDK动态代理和Cglib的动态代理
最简单的是静态代理方法,即代理模式,这里就不多啰嗦了。。重点说一下JDK的动态代理和Cglib的动态代理吧先说JDK的,需要被代理的类需要有接口,否则无法实现package proxy.dynamic;public interface IBook {void add();}实现接口
Wesley13 Wesley13
3年前
CGLIB介绍与原理(通过继承的动态代理)
一、什么是CGLIB?CGLIB是一个功能强大,高性能的代码生成包。它为没有实现接口的类提供代理,为JDK的动态代理提供了很好的补充。通常可以使用Java的动态代理创建代理,但当要代理的类没有实现接口或者为了更好的性能,CGLIB是一个好的选择。二、CGLIB原理CGLIB原理:动态生成一个要代理类的子类,子类重写要代理的类的所有不是final的
Wesley13 Wesley13
3年前
00:Java简单了解
浅谈Java之概述Java是SUN(StanfordUniversityNetwork),斯坦福大学网络公司)1995年推出的一门高级编程语言。Java是一种面向Internet的编程语言。随着Java技术在web方面的不断成熟,已经成为Web应用程序的首选开发语言。Java是简单易学,完全面向对象,安全可靠,与平台无关的编程语言。
Wesley13 Wesley13
3年前
CGLIB代理基础
  本文意在讲解CGLIB的基础使用及基本原理。一、CGLIB的基本原理:  依赖ASM字节码工具,通过动态生成实现接口或继承类的类字节码,实现动态代理。  针对接口,生成实现接口的类,即implements方式;针对类,生成继承父类的类,即extends方式。二、为什么使用CGLIB?  JDK的动态代理只能基于接口,有时候我们想基于类
Wesley13 Wesley13
3年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
Python进阶者 Python进阶者
9个月前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这