Java 动态代理的简单使用和理解


  • 前言
  • JDK 动态代理
    • 代理类
  • CGLIB 动态代理
    • 代理类
    • Spring @Configuration
  • 小结
  • 结语

前言1

另外,代理类还获取了 Object 的 hashCode、equals 和 toString 方法,它们的调用逻辑都是一样的,就是直接调用 InvocationHandler 对象对应的方法,比如:

public final int hashCode() throws  {
  try {
    return (Integer)super.h.invoke(this, m0, (Object[])null);
  } catch (RuntimeException | Error var2) {
    throw var2;
  } catch (Throwable var3) {
    throw new UndeclaredThrowableException(var3);
  }
}

因此,我们也是可以代理目标对象的这些方法的。

CGLIB 动态代理2:

public class TargetClass$$EnhancerByCGLIB$$eb42b691 extends TargetClass implements Factory {
  private MethodInterceptor CGLIB$CALLBACK_0;

  static void CGLIB$STATICHOOK1() {
    // 要代理的目标方法
    var10000 = ReflectUtils.findMethods(new String[]{"targetMethodA", "()V", "targetMethodB", "()V"}, (var1 = Class.forName("TargetClass")).getDeclaredMethods());
    CGLIB$targetMethodA$0$Method = var10000[0];
    CGLIB$targetMethodA$0$Proxy = MethodProxy.create(var1, var0, "()V", "targetMethodA", "CGLIB$targetMethodA$0");
    CGLIB$targetMethodB$1$Method = var10000[1];
    CGLIB$targetMethodB$1$Proxy = MethodProxy.create(var1, var0, "()V", "targetMethodB", "CGLIB$targetMethodB$1");
  }

  // 目标方法的简单代理
  final void CGLIB$targetMethodA$0() {
    super.targetMethodA();
  }

  public final void targetMethodA() {
    MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
    if (var10000 == null) {
      CGLIB$BIND_CALLBACKS(this);
      var10000 = this.CGLIB$CALLBACK_0;
    }

    // 当 MethodInterceptor 不为空时通过 MethodInterceptor 调用目标方法
    if (var10000 != null) {
      var10000.intercept(this, CGLIB$targetMethodA$0$Method, CGLIB$emptyArgs, CGLIB$targetMethodA$0$Proxy);
    } else {
      super.targetMethodA();
    }
  }

  // 目标方法的简单代理
  final void CGLIB$targetMethodB$1() {
    super.targetMethodB();
  }

  public final void targetMethodB() {
    MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
    if (var10000 == null) {
      CGLIB$BIND_CALLBACKS(this);
      var10000 = this.CGLIB$CALLBACK_0;
    }

    // 当 MethodInterceptor 不为空时通过 MethodInterceptor 调用目标方法
    if (var10000 != null) {
      var10000.intercept(this, CGLIB$targetMethodB$1$Method, CGLIB$emptyArgs, CGLIB$targetMethodB$1$Proxy);
    } else {
      super.targetMethodB();
    }
  }

  final int CGLIB$hashCode$5() {
    return super.hashCode();
  }

  // 对 Object 方法的代理
  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$5$Method, CGLIB$emptyArgs, CGLIB$hashCode$5$Proxy);
      return var1 == null ? 0 : ((Number)var1).intValue();
    } else {
      return super.hashCode();
    }
  }

  // ...
}

可以看到

  • CGLIB 每个方法设置了两个代理,一个直接调用父类方法,另一个判断是否存在 MethodInterceptor 来进行调用
  • 代理类继承了 TargetClass, 和 JDK 动态代理中继承 Proxy 的方式不一样

当我们设置了 MethodInterceptor 以后,CGLIB 便可以通过 MethodInterceptor 来调用目标方法,另外,调用 MethodInterceptor.intercept 方法时传递的第一个参数为代理类实例, 因此,需要执行被代理的方法时,应该通过 MethodProxy.invokeSuper 来完成,如果使用 Method.invoke 的话就会导致无限递归调用。

Spring @Configuration1 最开始看到 InvocationHandler 这个接口的时候总以为它的第一个参数为 TargetObject

2 为了方便阅读省略了很多其他不必要的内容