cglib动态代理拦截器中使用MethodProxy#invokeSuper和invoke的区别

    技术2024-10-27  19

    cglib动态代理拦截器中使用MethodProxy#invokeSuper和invoke的区别

    动态代理类调用过程MethodProxy#invokeMethodProxy#invokeSuper

    动态代理类

    生成动态代理对象时, 假设被代理类BaseClass有方法method1, 则在动态代理类中, 会对BaseClass的method1方法生成两个代理方法, 一个为CGLIB$method1, 内容类似于:

    final void CGLIB$method1() throws Throwable { super.finalize(); }

    另一个为method1,其中method1调用拦截器的intercept方法, 内容类似于:

    public final void method1(){ ... MethodInterceptor interceptor= this.CGLIB$CALLBACK_0; ... ... //调用拦截器,this就是当前的代理类 interceptor.intercept(this, CGLIB$method1$0$Method, CGLIB$emptyArgs,CGLIB$method1$0$Proxy); ... }

    代理类中对被代理类的每个可见方法都创建了一个methodProxy对象, 该对象是通过调用MethodProxy.create方法创建的代理类, 其中存储了被代理类的Class f2, 动态代理类的Class f1, 以及上面两个方法的index

    调用过程

    MethodProxy#invoke

    f1是被代理类的FastClass, i1是method1在被代理类中对应的Index

    将参数obj转型为f1对应的类型,按照i1调用obj对象的method1方法

    如果obj不是代理对象,则相当于直接调用原对象的method1 否则在就是调用动态代理类的method1方法, 会在其中再次调用拦截器

    如果传入的obj是被代理类的对象, 那么在method1中再调用其他方法是不会触发拦截的, spring的动态代理就是这样做的 如果传入的obj是代理对象, 会递归死循环调用method1的拦截器, 触发报错

    MethodProxy#invokeSuper

    f2是动态代理类的FastClass, i2对应CGLIB$method1

    将obj参数强制转型为f2, obj只能传入动态代理类的对象, 否则会转型失败然后调用传入按照i2调用obj对象的CGLIB$method1方法

    更通俗的理解: invokeSuper调用的是被代理类的方法, 但只有代理类才存在基类, 必须使用代理类作为obj参数调用 invoke调用的是增强方法, 必须使用被代理类的对象调用, 使用代理类会造成OOM

    Processed: 0.011, SQL: 9