CGLib Proxy 原理

2023年 10月 8日 45.2k 0

工程依赖

第一种方式:引入 cglib 依赖。


    cglib
    cglib

第二种方式:引入 spring-core 依赖。

方便起见,Spring 将 CGLIB 的代码拷贝到了 spring-core 工程中,并做了一些适配工作,以下是 spring-core 工程 package-info.java 文件中的注释:

Spring's repackaging of CGLIB 3.3 (with Spring-specific patches; for internal use only). This repackaging technique avoids any potential conflicts with dependencies on CGLIB at the application level or from third-party libraries and frameworks. As this repackaging happens at the class file level, sources and javadocs are not available here.

引入 spring-core 或者任何包含 spring-core 的依赖都行,这里我们引入 spring-context 依赖。


    org.springframework
    spring-context

CGLib Proxy 使用步骤

Enhancer 类用于生成代理类和代理对象,使用步骤如下:

  • 调用 setSuperclass() 设置代理类的父类,传入 Class 或 Interface 均可。
  • 调用 setCallback() 设置代理方法回调。Callback 是 Marker Interface,一般使用其子接口 MethodInterceptor
  • 调用 create() 方法创建代理对象,或者调用 createClass() 仅创建代理类而不创建代理对象。创建代理对象会使用 callbacks,而创建代理类则不会。
  • // 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.
    // The original and most general callback type is the MethodInterceptor, which in AOP terms enables "around advice"--that is, you can invoke custom code both before and after the invocation of the "super" method. In addition you can modify the arguments before calling the super method, or not call it at all.
    public class Enhancer extends AbstractClassGenerator {
    
        // Set the class which the generated class will extend. As a convenience, if the supplied superclass is actually an interface, setInterfaces will be called with the appropriate argument instead. A non-interface argument must not be declared as final, and must have an accessible constructor.
        public void setSuperclass(Class superclass) {
    
            if (superclass != null && superclass.isInterface()) {
                setInterfaces(new Class[]{superclass});
                // SPRING PATCH BEGIN
                setContextClass(superclass);
                // SPRING PATCH END
            }
            else if (superclass != null && superclass.equals(Object.class)) {
                // affects choice of ClassLoader
                this.superclass = null;
            }
            else {
                this.superclass = superclass;
                // SPRING PATCH BEGIN
                setContextClass(superclass);
                // SPRING PATCH END
            }
        }
    
        // Set the single Callback to use.
        public void setCallback(final Callback callback) {
            setCallbacks(new Callback[]{callback});
        }
    
        // 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.
        public Object create() {
            classOnly = false;
            argumentTypes = null;
            return createHelper();
        }
    
        // Generate a new class if necessary and return it without creating a new instance. This ignores any callbacks that have been set. To create a new instance you will have to use reflection, and methods called during the constructor will not be intercepted. To avoid this problem, use the multi-arg create method.
        public Class createClass() {
            classOnly = true;
            return (Class) createHelper();
        }
    

    MethodInterceptor:Around advice,代理方法的回调函数,调用代理对象的方法将触发 MethodInterceptor#invoke() 方法,在 invoke() 方法内部有两种执行 original method 的方法:使用反射或者使用 FastClass,使用 FastClass 速度会更快。normal reflection using the Method object, or by using the MethodProxy (faster).

    invoke() 方法参数:

  • obj – 代理对象。
  • method – 被代理类的方法。
  • args – 方法参数。
  • proxyMethodProxy 对象,invoke() 方法用于执行被代理类的方法,invokeSuper() 用于执行代理类的方法。
  • // General-purpose Enhancer callback which provides for "around advice".
    public interface MethodInterceptor
    extends Callback
    {
    
        // All generated proxied methods call this method instead of the original method. The original method may either be invoked by normal reflection using the Method object, or by using the MethodProxy (faster).
        // Params:
        //    obj – "this", the enhanced object
        //    method – intercepted Method
        //    args – argument array; primitive types are wrapped
        //    proxy – used to invoke super (non-intercepted method); may be called as many times as needed
        // Returns:any value compatible with the signature of the proxied method. Method returning void will ignore this value.
        public Object intercept(Object obj, java.lang.reflect.Method method, Object[] args, MethodProxy proxy) throws Throwable;
    

    通过 Enhancer 创建 userService 的代理对象:userServiceProxy

    public static void main(String[] args) {
        System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "cglib/");
        Enhancer enhancer = new Enhancer();
        UserService userService = new UserServiceImpl();
        enhancer.setSuperclass(userService.getClass());
        enhancer.setCallback(new MethodInterceptorImpl(userService));
        UserService userServiceProxy = (UserService) enhancer.create();
        User user = userService.getUserById(1L);
        System.out.println(user);
        user = userServiceProxy.getUserById(2L);
        System.out.println(user);
    }
    

    MethodInterceptorImpl 继承了 MethodInterceptor 接口,实现了方法回调逻辑。在 invoke() 方法中执行了 Object retVal = proxy.invoke(target, args),触发 original method 的调用。

    @RequiredArgsConstructor
    public class MethodInterceptorImpl implements MethodInterceptor {
    
        private final Object target;
    
        @Override
        public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
            System.out.println("preparing to execute method");
            Object retVal = proxy.invoke(target, args);
            System.out.println("execute method finished");
            return retVal;
        }
    
    }
    

    程序运行结果:

    CGLIB debugging enabled, writing to 'cglib/'
    querying user from db
    User(id=1, username=oneby1, createTime=Sun Apr 23 10:12:31 UTC 2023)
    preparing to execute method
    querying user from db
    execute method finished
    User(id=2, username=oneby2, createTime=Sun Apr 23 10:12:31 UTC 2023)
    

    CGLib Proxy 四种组合

    在 CGLib 中,一般使用速度更快的 MethodProxy 执行方法调用,不会使用 Method method 反射调用 original method,所以下面我们只关注如何通过 MethodProxy 执行方法调用。

    proxy.invoke(target, args)

    在上面的例程中,我们执行 MethodProxy#invoke(target, args) 触发 original method 的调用,注意 target 是被代理对象。

    Object retVal = proxy.invoke(target, args);
    

    invoke() 方法的参数:

    UserServiceImpl 中的 this 为被代理对象:

    proxy.invokeSuper(obj, args)

    换个方式,这次我们执行 MethodProxy#invokeSuper(obj, args) 触发 original method 的调用,注意 obj 是代理对象。

    Object retVal = proxy.invokeSuper(obj, args);
    

    程序输出结果与 proxy.invoke(target, args) 相同。

    CGLIB debugging enabled, writing to 'cglib/'
    querying user from db
    User(id=1, username=oneby1, createTime=Sun Apr 23 11:21:51 UTC 2023)
    preparing to execute method
    querying user from db
    execute method finished
    User(id=2, username=oneby2, createTime=Sun Apr 23 11:21:51 UTC 2023)
    

    UserServiceImpl 中的 this 为代理对象,怎么样?是不是懵了。

    proxy.invokeSuper(target, args)

    尝试通过 MethodProxy#invokeSuper(target, args) 触发 original method 的调用。

    Object retVal = proxy.invokeSuper(target, args);
    

    执行 proxy.invokeSuper(target, args) 方法时抛 ClassCastException 异常:UserServiceImpl 类不能强转为 UserServiceImpl$$EnhancerByCGLIB$$8daced35 类。

    CGLIB debugging enabled, writing to 'cglib/'
    querying user from db
    User(id=1, username=oneby1, createTime=Sun Apr 23 11:22:39 UTC 2023)
    preparing to execute method
    Exception in thread "main" java.lang.ClassCastException: class com.oneby.spring.aop.proxy.cglib.UserServiceImpl cannot be cast to class com.oneby.spring.aop.proxy.cglib.UserServiceImpl$$EnhancerByCGLIB$$8daced35 (com.oneby.spring.aop.proxy.cglib.UserServiceImpl and com.oneby.spring.aop.proxy.cglib.UserServiceImpl$$EnhancerByCGLIB$$8daced35 are in unnamed module of loader 'app')
        at com.oneby.spring.aop.proxy.cglib.UserServiceImpl$$EnhancerByCGLIB$$8daced35$$FastClassByCGLIB$$f44d7887.invoke()
        at org.springframework.cglib.proxy.MethodProxy.invokeSuper(MethodProxy.java:257)
        at com.oneby.spring.aop.proxy.cglib.MethodInterceptorImpl.intercept(MethodInterceptorImpl.java:21)
        at com.oneby.spring.aop.proxy.cglib.UserServiceImpl$$EnhancerByCGLIB$$8daced35.getUserById()
        at com.oneby.spring.aop.proxy.cglib.CglibProxyApplication.main(CglibProxyApplication.java:22)
    

    proxy.invoke(obj, args)

    尝试通过 MethodProxy#invoke(obj, args) 触发 original method 的调用。

    Object retVal = proxy.invoke(obj, args);
    

    执行 proxy.invoke(obj, args) 方法时发生无限递归调用,抛出 StackOverflowError 异常。

    // 省略很多个 preparing to execute method
    preparing to execute method
    preparing to execute method
    preparing to execute method
    preparing to execute method
    preparing to execute method
    preparing to execute method
    Exception in thread "main" java.lang.StackOverflowError
        at java.base/java.nio.ByteBuffer.position(ByteBuffer.java:1516)
        at java.base/java.nio.ByteBuffer.position(ByteBuffer.java:267)
    

    MethodProxy 和 FastClass

    想要解释上面四种组合现象,就需要先了解 CGLib 中两个非常重要的类:MethodProxyFastClass

    MethodProxy 类有两个非常重要的方法:invoke()invokeSuper()。从名字上来理解,invoke() 执行 obj 对象的方法,invokeSuper() 执行 obj 对象父类的方法,确实是这个意思,但哪来的父类呢?别忘了,CGLib 是基于继承实现的代理。

    // Classes generated by Enhancer pass this object to the registered MethodInterceptor objects when an intercepted method is invoked. It can be used to either invoke the original method, or call the same method on a different object of the same type.
    public class MethodProxy {
    
        // Invoke the original method, on a different object of the same type.
        // obj – the compatible object; recursion will result if you use the object passed as the first argument to the MethodInterceptor (usually not what you want)
        // args – the arguments passed to the intercepted method; you may substitute a different argument array as long as the types are compatible
        public Object invoke(Object obj, Object[] args) throws Throwable {
            try {
                init();
                FastClassInfo fci = fastClassInfo;
                return fci.f1.invoke(fci.i1, obj, args);
            }
            catch (InvocationTargetException ex) {
                throw ex.getTargetException();
            }
            catch (IllegalArgumentException ex) {
                if (fastClassInfo.i1 < 0)
                    throw new IllegalArgumentException("Protected method: " + sig1);
                throw ex;
            }
        }
    
        // Invoke the original (super) method on the specified object.
        // obj – the enhanced object, must be the object passed as the first argument to the MethodInterceptor
        // args – the arguments passed to the intercepted method; you may substitute a different argument array as long as the types are compatible
        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() 方法调用了 fci.f1.invoke(fci.i1, obj, args)invokeSuper() 方法调用了 fci.f2.invoke(fci.i2, obj, args),那么 fci.f1fci.f2 有什么区别呢?fci.f1.invoke()fci.f2.invoke() 方法中的 obj 参数又有什么区别呢?先看一下执行 MethodInterceptor#invoke() 方法时候,参数 MethodProxy proxy 中的 FastClass

    MethodProxy 中的 f1f2 均为 FastClass 类型,翻译成中文为 快类。什么叫快类呢?就是执行速度比 JDK Proxy 快的类。通过调用方式 f1.invoke(fci.i1, obj, args) 猜测:i1i2 应该是方法对应的索引。

    public class MethodProxy {
    
        private static class FastClassInfo {
    
            FastClass f1;
    
            FastClass f2;
    
            int i1;
    
            int i2;
        }
    

    那么 MethodProxy 如何初始化 FastClassInfo fastClassInfo 这个字段呢?一般是懒加载的方式初始化。

    MethodProxy 的静态工厂方法可以创建 MethodProxy 实例:public static MethodProxy create(Class c1, Class c2, String desc, String name1, String name2)。有两个类:Class c1Class c2,两个方法名称:String name1String name2Class c1 + String name1 可以确定被代理类的方法签名,Class c2 + String name2 可以确定代理类的方法签名。

    对于 if (!c1.isInterface() && c1 != Object.class && !Factory.class.isAssignableFrom(c2)) 条件判断,UserServiceImpl 类既不是接口,也不是 Object.class,也不是 Factory 的子类,不会执行 proxy.init() 初始化流程,fastClassInfo 对象会在 MethodProxy 相关方法第一次调用时被初始化。

    init() 方法中:fci.f1 = helper(ci, ci.c1)fci.f2 = helper(ci, ci.c2) 分别创建了 f1f2 对象,fci.i1 = fci.f1.getIndex(sig1)fci.i2 = fci.f2.getIndex(sig2) 分别获取了方法对应的索引。f1 + i1 能够确认被代理类的方法,f2 + i2 能够确认代理类的方法。

    public class MethodProxy {
    
        private Signature sig1;
    
        private Signature sig2;
    
        private CreateInfo createInfo;
    
        private final Object initLock = new Object();
    
        private volatile FastClassInfo fastClassInfo;
    
        // For internal use by Enhancer only; see the org.springframework.cglib.reflect.FastMethod class for similar functionality.
        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);
            proxy.createInfo = new CreateInfo(c1, c2);
    
            // SPRING PATCH BEGIN
            if (!c1.isInterface() && c1 != Object.class && !Factory.class.isAssignableFrom(c2)) {
                // Try early initialization for overridden methods on specifically purposed subclasses
                try {
                    proxy.init();
                }
                catch (CodeGenerationException ex) {
                    // Ignore - to be retried when actually needed later on (possibly not at all)
                }
            }
            // SPRING PATCH END
    
            return proxy;
        }
    
        private void init() {
            /*
             * Using a volatile invariant allows us to initialize the FastClass and
             * method index pairs atomically.
             *
             * 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();
                        fci.f1 = helper(ci, ci.c1);
                        fci.f2 = helper(ci, ci.c2);
                        fci.i1 = fci.f1.getIndex(sig1);
                        fci.i2 = fci.f2.getIndex(sig2);
                        fastClassInfo = fci;
                        createInfo = null;
                    }
                }
            }
        }
    

    执行 MethodProxy#create() 方法创建 MethodProxy 对象:

    第一次调用 MethodProxy 对象的相关方法时,触发 init() 方法执行 FastClass 对象的懒加载:

    生成 FastClass 对象:创建 FastClass.Generator g = new FastClass.Generator() 对象并设置相关属性,调用 g.create() 生成 FastClass 对象。

    public class MethodProxy {
    
        private static class CreateInfo {
    
            Class c1;
    
            Class c2;
    
            NamingPolicy namingPolicy;
    
            GeneratorStrategy strategy;
    
            boolean attemptLoad;
    
            public CreateInfo(Class c1, Class c2) {
                this.c1 = c1;
                this.c2 = c2;
                AbstractClassGenerator fromEnhancer = AbstractClassGenerator.getCurrent();
                if (fromEnhancer != null) {
                    namingPolicy = fromEnhancer.getNamingPolicy();
                    strategy = fromEnhancer.getStrategy();
                    attemptLoad = fromEnhancer.getAttemptLoad();
                }
            }
        }
    
        private static FastClass helper(CreateInfo ci, Class type) {
            FastClass.Generator g = new FastClass.Generator();
            g.setType(type);
            // SPRING PATCH BEGIN
            g.setContextClass(type);
            // SPRING PATCH END
            g.setClassLoader(ci.c2.getClassLoader());
            g.setNamingPolicy(ci.namingPolicy);
            g.setStrategy(ci.strategy);
            g.setAttemptLoad(ci.attemptLoad);
            return g.create();
        }
    

    FastClass 是抽象类,FastClass.Generator() 负责生成 FastClass 的子类。FastClass 类中的两个重要方法:

    getIndex():获取方法对应的索引。

    invoke():根据方法索引执行对应方法。

    abstract public class FastClass
    
        // Invoke the method with the specified index.
        // index – the method index
        // obj – the object the underlying method is invoked from
        // args – the arguments used for the method call
        abstract public Object invoke(int index, Object obj, Object[] args) throws InvocationTargetException;
    
        abstract public int getIndex(Signature sig);
    

    CGLib Proxy Class 文件解析

    在生成代理对象的代码之前, 加上这句 System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "cglib/"),可以在工程的 cglib 目录下生成 CGLib Proxy 对应的 Class 文件。

    UserServiceImpl$$EnhancerByCGLIB$$8daced35

    UserServiceImpl$$EnhancerByCGLIB$$8daced35 为代理类,该类继承了 UserServiceImpl,实现了 Factory 接口。这也印证了 CGLib 是基于继承的代理。

    public class UserServiceImpl$$EnhancerByCGLIB$$8daced35 extends UserServiceImpl 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$getUserById$0$Method;
        private static final MethodProxy CGLIB$getUserById$0$Proxy;
        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;
    
        static void CGLIB$STATICHOOK1() {
            CGLIB$THREAD_CALLBACKS = new ThreadLocal();
            CGLIB$emptyArgs = new Object[0];
            Class var0 = Class.forName("com.oneby.spring.aop.proxy.cglib.UserServiceImpl$$EnhancerByCGLIB$$8daced35");
            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$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");
            CGLIB$getUserById$0$Method = ReflectUtils.findMethods(new String[]{"getUserById", "(Ljava/lang/Long;)Lcom/oneby/spring/aop/proxy/domain/User;"}, (var1 = Class.forName("com.oneby.spring.aop.proxy.cglib.UserServiceImpl")).getDeclaredMethods())[0];
            CGLIB$getUserById$0$Proxy = MethodProxy.create(var1, var0, "(Ljava/lang/Long;)Lcom/oneby/spring/aop/proxy/domain/User;", "getUserById", "CGLIB$getUserById$0");
        }
    
        final User CGLIB$getUserById$0(Long var1) {
            return super.getUserById(var1);
        }
    
        public final User getUserById(Long var1) {
            MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
            if (var10000 == null) {
                CGLIB$BIND_CALLBACKS(this);
                var10000 = this.CGLIB$CALLBACK_0;
            }
    
            return var10000 != null ? (User)var10000.intercept(this, CGLIB$getUserById$0$Method, new Object[]{var1}, CGLIB$getUserById$0$Proxy) : super.getUserById(var1);
        }
    
        final boolean CGLIB$equals$1(Object var1) {
            return super.equals(var1);
        }
    
        public final boolean equals(Object var1) {
            MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
            if (var10000 == null) {
                CGLIB$BIND_CALLBACKS(this);
                var10000 = this.CGLIB$CALLBACK_0;
            }
    
            if (var10000 != null) {
                Object var2 = var10000.intercept(this, CGLIB$equals$1$Method, new Object[]{var1}, CGLIB$equals$1$Proxy);
                return var2 == null ? false : (Boolean)var2;
            } else {
                return super.equals(var1);
            }
        }
    
        final String CGLIB$toString$2() {
            return super.toString();
        }
    
        public final String toString() {
            MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
            if (var10000 == null) {
                CGLIB$BIND_CALLBACKS(this);
                var10000 = this.CGLIB$CALLBACK_0;
            }
    
            return var10000 != null ? (String)var10000.intercept(this, CGLIB$toString$2$Method, CGLIB$emptyArgs, CGLIB$toString$2$Proxy) : super.toString();
        }
    
        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();
            }
        }
    
        final Object CGLIB$clone$4() throws CloneNotSupportedException {
            return super.clone();
        }
    
        protected final Object clone() throws CloneNotSupportedException {
            MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
            if (var10000 == null) {
                CGLIB$BIND_CALLBACKS(this);
                var10000 = this.CGLIB$CALLBACK_0;
            }
    
            return var10000 != null ? var10000.intercept(this, CGLIB$clone$4$Method, CGLIB$emptyArgs, CGLIB$clone$4$Proxy) : super.clone();
        }
    
        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 1337399358:
                if (var10000.equals("getUserById(Ljava/lang/Long;)Lcom/oneby/spring/aop/proxy/domain/User;")) {
                    return CGLIB$getUserById$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 UserServiceImpl$$EnhancerByCGLIB$$8daced35() {
            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) {
            UserServiceImpl$$EnhancerByCGLIB$$8daced35 var1 = (UserServiceImpl$$EnhancerByCGLIB$$8daced35)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];
            }
    
        }
    
        public Object newInstance(Callback[] var1) {
            CGLIB$SET_THREAD_CALLBACKS(var1);
            UserServiceImpl$$EnhancerByCGLIB$$8daced35 var10000 = new UserServiceImpl$$EnhancerByCGLIB$$8daced35();
            CGLIB$SET_THREAD_CALLBACKS((Callback[])null);
            return var10000;
        }
    
        public Object newInstance(Callback var1) {
            CGLIB$SET_THREAD_CALLBACKS(new Callback[]{var1});
            UserServiceImpl$$EnhancerByCGLIB$$8daced35 var10000 = new UserServiceImpl$$EnhancerByCGLIB$$8daced35();
            CGLIB$SET_THREAD_CALLBACKS((Callback[])null);
            return var10000;
        }
    
        public Object newInstance(Class[] var1, Object[] var2, Callback[] var3) {
            CGLIB$SET_THREAD_CALLBACKS(var3);
            UserServiceImpl$$EnhancerByCGLIB$$8daced35 var10000 = new UserServiceImpl$$EnhancerByCGLIB$$8daced35;
            switch(var1.length) {
            case 0:
                var10000.();
                CGLIB$SET_THREAD_CALLBACKS((Callback[])null);
                return var10000;
            default:
                throw new IllegalArgumentException("Constructor not found");
            }
        }
    
        public Callback getCallback(int var1) {
            CGLIB$BIND_CALLBACKS(this);
            MethodInterceptor var10000;
            switch(var1) {
            case 0:
                var10000 = this.CGLIB$CALLBACK_0;
                break;
            default:
                var10000 = null;
            }
    
            return var10000;
        }
    
        public void setCallback(int var1, Callback var2) {
            switch(var1) {
            case 0:
                this.CGLIB$CALLBACK_0 = (MethodInterceptor)var2;
            default:
            }
        }
    
        public Callback[] getCallbacks() {
            CGLIB$BIND_CALLBACKS(this);
            return new Callback[]{this.CGLIB$CALLBACK_0};
        }
    
        public void setCallbacks(Callback[] var1) {
            this.CGLIB$CALLBACK_0 = (MethodInterceptor)var1[0];
        }
    
        static {
            CGLIB$STATICHOOK1();
        }
    }
    

    代理类中 getUserById() 方法的执行逻辑:

    先去拿 this.CGLIB$CALLBACK_0,拿不到则执行 CGLIB$BIND_CALLBACKS(this) 初始化 this.CGLIB$CALLBACK_0this.CGLIB$CALLBACK_0 就是代理方法回调函数,即 MethodInterceptorImpl 对象。

    检查 this.CGLIB$CALLBACK_0 是否存在,如果不存在,则直接执行父类方法 super.getUserById(var1),如果存在,则执行代理回调方法 (User)var10000.intercept(this, CGLIB$getUserById$0$Method, new Object[]{var1}, CGLIB$getUserById$0$Proxy)

    传入回调方法的参数为:

  • this:代理对象自身,即 UserServiceImpl$$EnhancerByCGLIB$$8daced35 对象。
  • CGLIB$getUserById$0$MethodMethod 对象,在静态代码块中被初始化为 UserServiceImpl#getUserById() 方法。
  • new Object[]{var1}:方法参数。
  • CGLIB$getUserById$0$ProxyMethodProxy 对象,在静态代码快中被初始化。
  • MethodProxy 初始化:

  • FastClass f1:被代理类(UserServiceImpl)的 FastClass,对应于后文中 UserServiceImpl$$FastClassByCGLIB$$85f1ad0e 类。
  • FastClass f2:被代理类(UserServiceImpl$$EnhancerByCGLIB$$8daced35)的 FastClass,对应于后文中的 UserServiceImpl$$EnhancerByCGLIB$$8daced35$$FastClassByCGLIB$$f44d7887 类。
  • int i1getUserById() 方法的索引。
  • int i2CGLIB$getUserById$0() 方法的索引。
  • static void CGLIB$STATICHOOK1() {
        CGLIB$THREAD_CALLBACKS = new ThreadLocal();
        CGLIB$emptyArgs = new Object[0];
        Class var0 = Class.forName("com.oneby.spring.aop.proxy.cglib.UserServiceImpl$$EnhancerByCGLIB$$8daced35");
        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$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");
        CGLIB$getUserById$0$Method = ReflectUtils.findMethods(new String[]{"getUserById", "(Ljava/lang/Long;)Lcom/oneby/spring/aop/proxy/domain/User;"}, (var1 = Class.forName("com.oneby.spring.aop.proxy.cglib.UserServiceImpl")).getDeclaredMethods())[0];
        CGLIB$getUserById$0$Proxy = MethodProxy.create(var1, var0, "(Ljava/lang/Long;)Lcom/oneby/spring/aop/proxy/domain/User;", "getUserById", "CGLIB$getUserById$0");
    }
    
    final User CGLIB$getUserById$0(Long var1) {
        return super.getUserById(var1);
    }
    
    public final User getUserById(Long var1) {
        MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
        if (var10000 == null) {
            CGLIB$BIND_CALLBACKS(this);
            var10000 = this.CGLIB$CALLBACK_0;
        }
    
        return var10000 != null ? (User)var10000.intercept(this, CGLIB$getUserById$0$Method, new Object[]{var1}, CGLIB$getUserById$0$Proxy) : super.getUserById(var1);
    }
    

    this.CGLIB$CALLBACK_0 字段的初始化逻辑:应该是生成代理类的时候,调用静态方法 CGLIB$SET_STATIC_CALLBACKS(),设置了 CGLIB$STATIC_CALLBACKS 静态字段的值,然后再将 CGLIB$STATIC_CALLBACKS 的值赋值给了 this.CGLIB$CALLBACK_0

    public static void CGLIB$SET_STATIC_CALLBACKS(Callback[] var0) {
        CGLIB$STATIC_CALLBACKS = var0;
    }
    
    private static final void CGLIB$BIND_CALLBACKS(Object var0) {
        UserServiceImpl$$EnhancerByCGLIB$$8daced35 var1 = (UserServiceImpl$$EnhancerByCGLIB$$8daced35)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];
        }
    
    }
    

    UserServiceImpl$$FastClassByCGLIB$$85f1ad0e

    UserServiceImpl$$FastClassByCGLIB$$85f1ad0e 是被代理类 UserServiceImpl 对应的 FastClass。该类使用 hashCode 方式执行 dispatch,比反射调用更加高效。该类转发 UserServiceImpl 类中的方法,比如 getUserById(Ljava/lang/Long;)Lcom/oneby/spring/aop/proxy/domain/User;

    UserServiceImpl$$FastClassByCGLIB$$85f1ad0e 类中实现了 FastClass 抽象类的方法:

  • public int getIndex(Signature var1):根据方法的 Signature 获取方法索引。
  • public int getIndex(String var1, Class[] var2):根据方法名称和方法参数类型获取方法索引。
  • public int getMaxIndex():获取最大的方法索引。
  • public Object invoke(int var1, Object var2, Object[] var3):根据方法索引执行对应方法。
  • public Object newInstance(int var1, Object[] var2):创建 UserServiceImpl$$FastClassByCGLIB$$85f1ad0e 实例,由 CGLib 调用创建此类的实例,我们用不到。
  • public class UserServiceImpl$$FastClassByCGLIB$$85f1ad0e extends FastClass {
        public UserServiceImpl$$FastClassByCGLIB$$85f1ad0e(Class var1) {
            super(var1);
        }
    
        public int getIndex(Signature var1) {
            String var10000 = var1.toString();
            switch(var10000.hashCode()) {
            case 1337399358:
                if (var10000.equals("getUserById(Ljava/lang/Long;)Lcom/oneby/spring/aop/proxy/domain/User;")) {
                    return 0;
                }
                break;
            case 1826985398:
                if (var10000.equals("equals(Ljava/lang/Object;)Z")) {
                    return 1;
                }
                break;
            case 1913648695:
                if (var10000.equals("toString()Ljava/lang/String;")) {
                    return 2;
                }
                break;
            case 1984935277:
                if (var10000.equals("hashCode()I")) {
                    return 3;
                }
            }
    
            return -1;
        }
    
        public int getIndex(String var1, Class[] var2) {
            switch(var1.hashCode()) {
            case -1776922004:
                if (var1.equals("toString")) {
                    switch(var2.length) {
                    case 0:
                        return 2;
                    }
                }
                break;
            case -1295482945:
                if (var1.equals("equals")) {
                    switch(var2.length) {
                    case 1:
                        if (var2[0].getName().equals("java.lang.Object")) {
                            return 1;
                        }
                    }
                }
                break;
            case 147696667:
                if (var1.equals("hashCode")) {
                    switch(var2.length) {
                    case 0:
                        return 3;
                    }
                }
                break;
            case 1810897843:
                if (var1.equals("getUserById")) {
                    switch(var2.length) {
                    case 1:
                        if (var2[0].getName().equals("java.lang.Long")) {
                            return 0;
                        }
                    }
                }
            }
    
            return -1;
        }
    
        public int getIndex(Class[] var1) {
            switch(var1.length) {
            case 0:
                return 0;
            default:
                return -1;
            }
        }
    
        public Object invoke(int var1, Object var2, Object[] var3) throws InvocationTargetException {
            UserServiceImpl var10000 = (UserServiceImpl)var2;
            int var10001 = var1;
    
            try {
                switch(var10001) {
                case 0:
                    return var10000.getUserById((Long)var3[0]);
                case 1:
                    return new Boolean(var10000.equals(var3[0]));
                case 2:
                    return var10000.toString();
                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 {
            UserServiceImpl var10000 = new UserServiceImpl;
            UserServiceImpl var10001 = var10000;
            int var10002 = var1;
    
            try {
                switch(var10002) {
                case 0:
                    var10001.();
                    return var10000;
                }
            } catch (Throwable var3) {
                throw new InvocationTargetException(var3);
            }
    
            throw new IllegalArgumentException("Cannot find matching method/constructor");
        }
    
        public int getMaxIndex() {
            return 3;
        }
    }
    

    这里的 invoke() 方法对应着 MethodProxy#invoke() 方法。invoke() 方法中使用 switch case 语法,通过方法索引转发方法。因为 UserServiceImpl$$FastClassByCGLIB$$85f1ad0e 只转发了被代理类的方法,所以这里的 Object var2 参数只能传入被代理对象。

    public Object invoke(int var1, Object var2, Object[] var3) throws InvocationTargetException {
        UserServiceImpl var10000 = (UserServiceImpl)var2;
        int var10001 = var1;
    
        try {
            switch(var10001) {
            case 0:
                return var10000.getUserById((Long)var3[0]);
            case 1:
                return new Boolean(var10000.equals(var3[0]));
            case 2:
                return var10000.toString();
            case 3:
                return new Integer(var10000.hashCode());
            }
        } catch (Throwable var4) {
            throw new InvocationTargetException(var4);
        }
    
        throw new IllegalArgumentException("Cannot find matching method/constructor");
    }
    

    通过以上分析,也就能解释为什么执行到 UserServiceImpl 类中,this 为被代理对象。来张图:CGLib Proxy 执行 invoke() 方法时UserServiceImpl 类的 this.jpg

    UserServiceImpl$$EnhancerByCGLIB$$8daced35$$FastClassByCGLIB$$f44d7887

    UserServiceImpl$$EnhancerByCGLIB$$8daced35$$FastClassByCGLIB$$f44d7887 是代理类 UserServiceImpl$$EnhancerByCGLIB$$8daced35 对应的 FastClass。该类同样也使用 hashCode 方式执行 dispatch,转发 UserServiceImpl$$EnhancerByCGLIB$$8daced35 类中的方法,比如 getUserById(Ljava/lang/Long;)Lcom/oneby/spring/aop/proxy/domain/User;CGLIB$getUserById$0(Ljava/lang/Long;)Lcom/oneby/spring/aop/proxy/domain/User;

    为什么这里会有两个 getUserById() 方法呢?由于代理类继承并重写了父类的 getUserById() 方法,所以调用该方法只能走代理逻辑。我们需要另外一个方法,不走代理逻辑,这个方法就是 CGLIB$getUserById$0()

    public class UserServiceImpl$$EnhancerByCGLIB$$8daced35$$FastClassByCGLIB$$f44d7887 extends FastClass {
        public UserServiceImpl$$EnhancerByCGLIB$$8daced35$$FastClassByCGLIB$$f44d7887(Class var1) {
            super(var1);
        }
    
        public int getIndex(Signature var1) {
            String var10000 = var1.toString();
            switch(var10000.hashCode()) {
            case -1882565338:
                if (var10000.equals("CGLIB$equals$1(Ljava/lang/Object;)Z")) {
                    return 19;
                }
                break;
            case -1870561232:
                if (var10000.equals("CGLIB$findMethodProxy(Lorg/springframework/cglib/core/Signature;)Lorg/springframework/cglib/proxy/MethodProxy;")) {
                    return 14;
                }
                break;
            case -1745842178:
                if (var10000.equals("setCallbacks([Lorg/springframework/cglib/proxy/Callback;)V")) {
                    return 9;
                }
                break;
            case -1641413109:
                if (var10000.equals("newInstance([Lorg/springframework/cglib/proxy/Callback;)Ljava/lang/Object;")) {
                    return 6;
                }
                break;
            case -1457535688:
                if (var10000.equals("CGLIB$STATICHOOK1()V")) {
                    return 18;
                }
                break;
            case -1411842725:
                if (var10000.equals("CGLIB$hashCode$3()I")) {
                    return 16;
                }
                break;
            case -1034266769:
                if (var10000.equals("CGLIB$SET_STATIC_CALLBACKS([Lorg/springframework/cglib/proxy/Callback;)V")) {
                    return 11;
                }
                break;
            case -1025895669:
                if (var10000.equals("CGLIB$SET_THREAD_CALLBACKS([Lorg/springframework/cglib/proxy/Callback;)V")) {
                    return 10;
                }
                break;
            case -988317324:
                if (var10000.equals("newInstance([Ljava/lang/Class;[Ljava/lang/Object;[Lorg/springframework/cglib/proxy/Callback;)Ljava/lang/Object;")) {
                    return 5;
                }
                break;
            case -508378822:
                if (var10000.equals("clone()Ljava/lang/Object;")) {
                    return 3;
                }
                break;
            case 180604647:
                if (var10000.equals("CGLIB$getUserById$0(Ljava/lang/Long;)Lcom/oneby/spring/aop/proxy/domain/User;")) {
                    return 15;
                }
                break;
            case 610042816:
                if (var10000.equals("newInstance(Lorg/springframework/cglib/proxy/Callback;)Ljava/lang/Object;")) {
                    return 4;
                }
                break;
            case 1132856532:
                if (var10000.equals("getCallbacks()[Lorg/springframework/cglib/proxy/Callback;")) {
                    return 13;
                }
                break;
            case 1246779367:
                if (var10000.equals("setCallback(ILorg/springframework/cglib/proxy/Callback;)V")) {
                    return 7;
                }
                break;
            case 1306468936:
                if (var10000.equals("CGLIB$toString$2()Ljava/lang/String;")) {
                    return 20;
                }
                break;
            case 1337399358:
                if (var10000.equals("getUserById(Ljava/lang/Long;)Lcom/oneby/spring/aop/proxy/domain/User;")) {
                    return 8;
                }
                break;
            case 1364367423:
                if (var10000.equals("getCallback(I)Lorg/springframework/cglib/proxy/Callback;")) {
                    return 12;
                }
                break;
            case 1800494055:
                if (var10000.equals("CGLIB$clone$4()Ljava/lang/Object;")) {
                    return 17;
                }
                break;
            case 1826985398:
                if (var10000.equals("equals(Ljava/lang/Object;)Z")) {
                    return 0;
                }
                break;
            case 1913648695:
                if (var10000.equals("toString()Ljava/lang/String;")) {
                    return 1;
                }
                break;
            case 1984935277:
                if (var10000.equals("hashCode()I")) {
                    return 2;
                }
            }
    
            return -1;
        }
    
        public int getIndex(String var1, Class[] var2) {
            switch(var1.hashCode()) {
            case -1776922004:
                if (var1.equals("toString")) {
                    switch(var2.length) {
                    case 0:
                        return 1;
                    }
                }
                break;
            case -1295482945:
                if (var1.equals("equals")) {
                    switch(var2.length) {
                    case 1:
                        if (var2[0].getName().equals("java.lang.Object")) {
                            return 0;
                        }
                    }
                }
                break;
            case -1154664548:
                if (var1.equals("CGLIB$getUserById$0")) {
                    switch(var2.length) {
                    case 1:
                        if (var2[0].getName().equals("java.lang.Long")) {
                            return 15;
                        }
                    }
                }
                break;
            case -1053468136:
                if (var1.equals("getCallbacks")) {
                    switch(var2.length) {
                    case 0:
                        return 13;
                    }
                }
                break;
            case -124978609:
                if (var1.equals("CGLIB$equals$1")) {
                    switch(var2.length) {
                    case 1:
                        if (var2[0].getName().equals("java.lang.Object")) {
                            return 19;
                        }
                    }
                }
                break;
            case -60403779:
                if (var1.equals("CGLIB$SET_STATIC_CALLBACKS")) {
                    switch(var2.length) {
                    case 1:
                        if (var2[0].getName().equals("[Lorg.springframework.cglib.proxy.Callback;")) {
                            return 11;
                        }
                    }
                }
                break;
            case -29025555:
                if (var1.equals("CGLIB$hashCode$3")) {
                    switch(var2.length) {
                    case 0:
                        return 16;
                    }
                }
                break;
            case 85179481:
                if (var1.equals("CGLIB$SET_THREAD_CALLBACKS")) {
                    switch(var2.length) {
                    case 1:
                        if (var2[0].getName().equals("[Lorg.springframework.cglib.proxy.Callback;")) {
                            return 10;
                        }
                    }
                }
                break;
            case 94756189:
                if (var1.equals("clone")) {
                    switch(var2.length) {
                    case 0:
                        return 3;
                    }
                }
                break;
            case 147696667:
                if (var1.equals("hashCode")) {
                    switch(var2.length) {
                    case 0:
                        return 2;
                    }
                }
                break;
            case 161998109:
                if (var1.equals("CGLIB$STATICHOOK1")) {
                    switch(var2.length) {
                    case 0:
                        return 18;
                    }
                }
                break;
            case 495524492:
                if (var1.equals("setCallbacks")) {
                    switch(var2.length) {
                    case 1:
                        if (var2[0].getName().equals("[Lorg.springframework.cglib.proxy.Callback;")) {
                            return 9;
                        }
                    }
                }
                break;
            case 1154623345:
                if (var1.equals("CGLIB$findMethodProxy")) {
                    switch(var2.length) {
                    case 1:
                        if (var2[0].getName().equals("org.springframework.cglib.core.Signature")) {
                            return 14;
                        }
                    }
                }
                break;
            case 1543336189:
                if (var1.equals("CGLIB$toString$2")) {
                    switch(var2.length) {
                    case 0:
                        return 20;
                    }
                }
                break;
            case 1810897843:
                if (var1.equals("getUserById")) {
                    switch(var2.length) {
                    case 1:
                        if (var2[0].getName().equals("java.lang.Long")) {
                            return 8;
                        }
                    }
                }
                break;
            case 1811874389:
                if (var1.equals("newInstance")) {
                    switch(var2.length) {
                    case 1:
                        String var10001 = var2[0].getName();
                        switch(var10001.hashCode()) {
                        case -1997738671:
                            if (var10001.equals("[Lorg.springframework.cglib.proxy.Callback;")) {
                                return 6;
                            }
                            break;
                        case 1364160985:
                            if (var10001.equals("org.springframework.cglib.proxy.Callback")) {
                                return 4;
                            }
                        }
                    case 2:
                    default:
                        break;
                    case 3:
                        if (var2[0].getName().equals("[Ljava.lang.Class;") && var2[1].getName().equals("[Ljava.lang.Object;") && var2[2].getName().equals("[Lorg.springframework.cglib.proxy.Callback;")) {
                            return 5;
                        }
                    }
                }
                break;
            case 1817099975:
                if (var1.equals("setCallback")) {
                    switch(var2.length) {
                    case 2:
                        if (var2[0].getName().equals("int") && var2[1].getName().equals("org.springframework.cglib.proxy.Callback")) {
                            return 7;
                        }
                    }
                }
                break;
            case 1905679803:
                if (var1.equals("getCallback")) {
                    switch(var2.length) {
                    case 1:
                        if (var2[0].getName().equals("int")) {
                            return 12;
                        }
                    }
                }
                break;
            case 1951977610:
                if (var1.equals("CGLIB$clone$4")) {
                    switch(var2.length) {
                    case 0:
                        return 17;
                    }
                }
            }
    
            return -1;
        }
    
        public int getIndex(Class[] var1) {
            switch(var1.length) {
            case 0:
                return 0;
            default:
                return -1;
            }
        }
    
        public Object invoke(int var1, Object var2, Object[] var3) throws InvocationTargetException {
            8daced35 var10000 = (8daced35)var2;
            int var10001 = var1;
    
            try {
                switch(var10001) {
                case 0:
                    return new Boolean(var10000.equals(var3[0]));
                case 1:
                    return var10000.toString();
                case 2:
                    return new Integer(var10000.hashCode());
                case 3:
                    return var10000.clone();
                case 4:
                    return var10000.newInstance((Callback)var3[0]);
                case 5:
                    return var10000.newInstance((Class[])var3[0], (Object[])var3[1], (Callback[])var3[2]);
                case 6:
                    return var10000.newInstance((Callback[])var3[0]);
                case 7:
                    var10000.setCallback(((Number)var3[0]).intValue(), (Callback)var3[1]);
                    return null;
                case 8:
                    return var10000.getUserById((Long)var3[0]);
                case 9:
                    var10000.setCallbacks((Callback[])var3[0]);
                    return null;
                case 10:
                    8daced35.CGLIB$SET_THREAD_CALLBACKS((Callback[])var3[0]);
                    return null;
                case 11:
                    8daced35.CGLIB$SET_STATIC_CALLBACKS((Callback[])var3[0]);
                    return null;
                case 12:
                    return var10000.getCallback(((Number)var3[0]).intValue());
                case 13:
                    return var10000.getCallbacks();
                case 14:
                    return 8daced35.CGLIB$findMethodProxy((Signature)var3[0]);
                case 15:
                    return var10000.CGLIB$getUserById$0((Long)var3[0]);
                case 16:
                    return new Integer(var10000.CGLIB$hashCode$3());
                case 17:
                    return var10000.CGLIB$clone$4();
                case 18:
                    8daced35.CGLIB$STATICHOOK1();
                    return null;
                case 19:
                    return new Boolean(var10000.CGLIB$equals$1(var3[0]));
                case 20:
                    return var10000.CGLIB$toString$2();
                }
            } catch (Throwable var4) {
                throw new InvocationTargetException(var4);
            }
    
            throw new IllegalArgumentException("Cannot find matching method/constructor");
        }
    
        public Object newInstance(int var1, Object[] var2) throws InvocationTargetException {
            8daced35 var10000 = new 8daced35;
            8daced35 var10001 = var10000;
            int var10002 = var1;
    
            try {
                switch(var10002) {
                case 0:
                    var10001.();
                    return var10000;
                }
            } catch (Throwable var3) {
                throw new InvocationTargetException(var3);
            }
    
            throw new IllegalArgumentException("Cannot find matching method/constructor");
        }
    
        public int getMaxIndex() {
            return 20;
        }
    }
    

    CGLIB$getUserById$0() 方法的定义在代理类 UserServiceImpl$$EnhancerByCGLIB$$8daced35 中,CGLIB$getUserById$0() 中执行了 return super.getUserById(var),调用父类方法,这也就是 MethodProxy#invokeSuper() 方法名称的由来。

    public class UserServiceImpl$$EnhancerByCGLIB$$8daced35 extends UserServiceImpl implements Factory {
    
        final User CGLIB$getUserById$0(Long var1) {
            return super.getUserById(var1);
        }
    
        public final User getUserById(Long var1) {
            MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
            if (var10000 == null) {
                CGLIB$BIND_CALLBACKS(this);
                var10000 = this.CGLIB$CALLBACK_0;
            }
    
            return var10000 != null ? (User)var10000.intercept(this, CGLIB$getUserById$0$Method, new Object[]{var1}, CGLIB$getUserById$0$Proxy) : super.getUserById(var1);
        }
    

    执行 super.getUserById(var) 会执行父类 UserServiceImpl 的方法,代码执行到 UserServiceImpl 类中,this 为代理对象。

    这里的 invoke() 方法对应着 MethodProxy#invokeSuper() 方法。invoke() 方法中使用 switch case 语法,通过方法索引转发方法。因为 UserServiceImpl$$EnhancerByCGLIB$$8daced35$$FastClassByCGLIB$$f44d7887 转发代理类的方法,所以这里的 Object var2 参数只能传入代理对象。

    public Object invoke(int var1, Object var2, Object[] var3) throws InvocationTargetException {
        8daced35 var10000 = (8daced35)var2;
        int var10001 = var1;
    
        try {
            switch(var10001) {
            case 0:
                return new Boolean(var10000.equals(var3[0]));
            case 1:
                return var10000.toString();
            case 2:
                return new Integer(var10000.hashCode());
            case 3:
                return var10000.clone();
            case 4:
                return var10000.newInstance((Callback)var3[0]);
            case 5:
                return var10000.newInstance((Callback[])var3[0]);
            case 6:
                return var10000.newInstance((Class[])var3[0], (Object[])var3[1], (Callback[])var3[2]);
            case 7:
                var10000.setCallback(((Number)var3[0]).intValue(), (Callback)var3[1]);
                return null;
            case 8:
                return var10000.getUserById((Long)var3[0]);
            case 9:
                return 8daced35.CGLIB$findMethodProxy((Signature)var3[0]);
            case 10:
                var10000.setCallbacks((Callback[])var3[0]);
                return null;
            case 11:
                8daced35.CGLIB$SET_THREAD_CALLBACKS((Callback[])var3[0]);
                return null;
            case 12:
                8daced35.CGLIB$SET_STATIC_CALLBACKS((Callback[])var3[0]);
                return null;
            case 13:
                return var10000.getCallback(((Number)var3[0]).intValue());
            case 14:
                return var10000.getCallbacks();
            case 15:
                8daced35.CGLIB$STATICHOOK1();
                return null;
            case 16:
                return new Boolean(var10000.CGLIB$equals$1(var3[0]));
            case 17:
                return var10000.CGLIB$toString$2();
            case 18:
                return var10000.CGLIB$clone$4();
            case 19:
                return new Integer(var10000.CGLIB$hashCode$3());
            case 20:
                return var10000.CGLIB$getUserById$0((Long)var3[0]);
            }
        } catch (Throwable var4) {
            throw new InvocationTargetException(var4);
        }
    
        throw new IllegalArgumentException("Cannot find matching method/constructor");
    }
    

    相关文章

    JavaScript2024新功能:Object.groupBy、正则表达式v标志
    PHP trim 函数对多字节字符的使用和限制
    新函数 json_validate() 、randomizer 类扩展…20 个PHP 8.3 新特性全面解析
    使用HTMX为WordPress增效:如何在不使用复杂框架的情况下增强平台功能
    为React 19做准备:WordPress 6.6用户指南
    如何删除WordPress中的所有评论

    发布评论