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 表示父类的方法。

posted @ 2020-08-25 23:32  strongmore  阅读(3107)  评论(0编辑  收藏  举报