在这里,我需要创建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);
    }
  }

最佳答案

您所描述的听起来像是混音模式。您不能简单地明确实现委托吗?就像是:

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反射来设置此字段。否则,您可以使用static字段

Forwarding.to(new A() {
  // A methods
});

10-07 13:55