如何使用cglib实现委派?

时间:2014-08-12 10:45:07

标签: java java-bytecode-asm cglib

在这里,我需要创建BImpl的实例,但BImpl需要通过接口A访问功能。为此,该类实现了此接口A。如何在运行时连接BImpl的这些接口方法的委托?我们的想法是BImpl可以使用A的方法。

在我的情况下,A已知并且AImpl实例是在运行时创建的。

public static void main(String[] args) {
  B b = (B) Enhancer.create(BImpl.class, new MyInterceptor());
  System.out.println(b.cellValue());
}

interface A {
  String value();
}

class AImpl implements A {

  @Override
  public String value() {
    return "MyA";
  }
}

interface B {
  String cellValue();
}

abstract class BImpl implements B, A {
  @Override
  public String cellValue() {
    return value() + "MyBCell";
  }
}

class MyInterceptor implements MethodInterceptor {

  @Override
  public Object intercept(Object obj, Method method, Object[] args,
                          MethodProxy proxy) throws Throwable {
    System.out.println(method.getName());
    if ("value".equals(method.getName()))
      return method.invoke(obj, args);
    else
      return proxy.invokeSuper(obj, args);
    }
  }

1 个答案:

答案 0 :(得分:3)

您所描述的内容听起来像 mixin 模式。你能不能简单地明确地实施一个代表团?类似的东西:

class BImpl implements B, A {

  private A a;

  public BImpl(A a) {
    this.a = a;
  }

  @Override
  public String cellValue() {
    return value() + "MyBCell";
  }

  @Override
  public String value() {
    return a.value();
  }
}

这应该是可能的,因为你说在编译期间你知道A

否则,如果您确实需要在运行时执行此操作,那么您的方法可能是cglib的正确方法。但是,在调用时,您需要为obj提供不同的实例:

return method.invoke(obj, args);

否则你再次调用截获的方法,通过在循环中点击MyMethodInterceptor找到自己的无限循环。你也可以safe yourself the branch and use a CallbkackFilter instead

如果您不受cglib的约束,您还可以查看我的库Byte Buddy,这使得这一切更具表现力:

new ByteBuddy()
  .subclass(BImpl.class)
  .method(isAnnotatedBy(A.class))
  .intercept(Forwarding.to("a", A.class))
  .make();

生成的类现在有一个字段a,您可以将其设置为任何A的实例,现在委托A接口方法的方法调用。您可以通过例如使用Java反射来设置此字段。否则,您可以使用{/ 1}}字段

static