ByteBuddy實現動態代理


介紹

ByteBuddy也是一個代碼生成和操作的類庫,可以在運行時動態創建和修改class,底層也是ASM庫,相比於cglib,javassist,Bytebuddy在性能上具有優勢,Hibernate的懶加載和mockito測試框架都使用到了Bytebuddy。官網

實現動態代理

maven依賴

<dependency>
  <groupId>net.bytebuddy</groupId>
  <artifactId>byte-buddy</artifactId>
  <version>1.10.13</version>
</dependency>

代理接口

/**
 * 可以唱歌的
 */
public interface Singable {
  /**
   * 唱歌
   */
  void sing();
}

被代理類

/**
 * 歌手
 */
public class Singer implements Singable {
  @Override
  public void sing() {
    System.out.println("I am singing...");
  }
}

通過代理接口實現

public class Client {

  public static void main(String[] args) throws Exception {
    Singable proxy = createByteBuddyDynamicProxy();
    proxy.sing();
    System.out.println(proxy.toString());
  }

  private static Singable createByteBuddyDynamicProxy() throws Exception {
    return (Singable) new ByteBuddy().subclass(Object.class)
        .implement(Singable.class)
        .method(ElementMatchers.named("sing"))
        .intercept(InvocationHandlerAdapter.of(new SingerInvocationHandler(new Singer())))
        .make()
        .load(Client.class.getClassLoader())
        .getLoaded()
        .getDeclaredConstructor()
        .newInstance();
  }

  public static class SingerInvocationHandler implements InvocationHandler {

    private Object delegate;

    public SingerInvocationHandler(Object delegate) {
      this.delegate = delegate;
    }

    /**
     * 動態代理調用方法
     *
     * @param proxy 生成的代理對象
     * @param method 代理的方法
     * @param args 方法參數
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
      System.out.println("bytebuddy proxy before sing ");
      Object ret = method.invoke(delegate, args);
      System.out.println("bytebuddy proxy after sing ");
      return ret;
    }

  }
}

繼承Object,實現Singable接口,通過適配JDK的InvocationHandler實現方法的攔截。

public class Client {

  public static void main(String[] args) throws Exception {
    Singable proxy = createByteBuddyDynamicProxy();
    proxy.sing();
    System.out.println(proxy.toString());
  }

  private static Singable createByteBuddyDynamicProxy() throws Exception {
    return (Singable) new ByteBuddy().subclass(Object.class)
        .implement(Singable.class)
        .method(ElementMatchers.named("sing"))
        .intercept(MethodDelegation.to(new SingerAgentInterceptor(new Singer())))
        .make()
        .load(Client.class.getClassLoader())
        .getLoaded()
        .getDeclaredConstructor()
        .newInstance();
  }

  public static class SingerAgentInterceptor {

    private Object delegate;

    public SingerAgentInterceptor(Object delegate) {
      this.delegate = delegate;
    }

    /**
     * @param proxy 代理對象
     * @param method 代理方法
     * @param args 方法參數
     */
    public Object interceptor(@This Object proxy, @Origin Method method,
        @AllArguments Object[] args) throws Exception {
      System.out.println("bytebuddy delegate proxy before sing ");
      Object ret = method.invoke(delegate, args);
      System.out.println("bytebuddy delegate proxy after sing ");
      return ret;
    }
  }

}

我們也可以通過方法委托(MethodDelegation)的方式實現攔截器,
@This 表示生成的代理對象
@Origin 表示被代理的方法
@AllArguments 表示方法參數

通過代理類實現

public class Client {

  public static void main(String[] args) throws Exception {
    Singable proxy = createByteBuddyDynamicProxy();
    proxy.sing();
    System.out.println(proxy.toString());
  }

  private static Singable createByteBuddyDynamicProxy() throws Exception {
    return (Singable) new ByteBuddy().subclass(Singer.class)
        .implement(Singable.class)
        .method(ElementMatchers.named("sing"))
        .intercept(MethodDelegation.to(new SingerAgentInterceptor()))
        .make()
        .load(Client.class.getClassLoader())
        .getLoaded()
        .getDeclaredConstructor()
        .newInstance();
  }

  public static class SingerAgentInterceptor {

    public Object interceptor(@This Object proxy, @Origin Method method,
        @SuperMethod Method superMethod,
        @AllArguments Object[] args) throws Exception {
      System.out.println("bytebuddy delegate proxy2 before sing ");
      Object ret = superMethod.invoke(proxy, args);
      System.out.println("bytebuddy delegate proxy2 after sing ");
      return ret;
    }
  }

}

繼承Singer類,@SuperMethod 表示父類的方法。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM