5

在 Java 中,可以使用InvocationHandler. 尽管 JVM 进行了优化,但使用反射调用方法总是会有一些开销。

为了尝试解决这个问题,我尝试使用 ByteBuddy 在运行时创建代理类,但是文档在这方面似乎不够清楚。

如何创建一个MethodCallProxy以便将方法调用转发到某个类实例?

编辑:

为了更好地澄清我的问题,我提供了一个我想要实现的示例:

我正在构建一个 RPC 系统。在方法调用的每一端,我都有一个定义契约的接口(当调用者/被调用者都在 JVM 下运行时)。

@Contract
interface ISomeService {
    fun someMethod(arg0: String, arg1: SomePojo): PojoResult
}

在调用站点,我注入了一个代理,它拦截所有方法调用并将它们转发给被调用者。

ByteBuddy()
    .subclass(Any::class.java)
    .implement(serviceClass)

    // Service contract method delegation
    .method(isDeclaredBy(serviceClass)).intercept(
      MethodDelegation
          .to(ServiceProxyInterceptor())
          .filter(not(isDeclaredBy(Any::class.java)))
    )

    .make()
    .load(this)
    .loaded as Class<T>

最后,在被调用方,我有几个处理程序,每个服务方法一个,负责解组调用参数并将它们转发到服务实现。

@Service
class SomeServiceImpl {
    fun someMethod(arg0: String, arg1: SomePojo): PojoResult {
        // ...
    }
}

我可以使用代码生成来解决这个问题,但是生成的jar文件可能会变得非常大。因此,我想创建这些处理程序的通用版本,并在每个实例中附加一个代理,该代理拦截每个方法调用ISomeService并将它们转发到SomeServiceImpl.

4

1 回答 1

9

在 Byte Buddy 中有多种创建代理类的方法。确切的方法取决于您的用例。最简单的方法可能是使用InvocationHandlerAdapter. 鉴于您想为 创建一个代理SomeClass,您可以使用以下方法创建一个:

Class<? extends SomeClass> proxy = new ByteBuddy()
  .subclass(SomeClass.class)
  .method(ElementMatchers.any())
  .intercept(InvocationHandlerAdapter.of(invocationHandler))
  .make()
  .load(SomeClass.class.getClassLoader());

如果您想创建一个代理到不同实例的代理,您将另外定义一个字段。这可以通过以下说明来完成:

Class<? extends SomeClass> proxy = new ByteBuddy()
  .subclass(SomeClass.class)
  .defineField("handler", InvocationHandler.class, Visibility.PUBLIC)
  .method(ElementMatchers.any())
  .intercept(InvocationHandlerAdapter.toField("handler"))
  .make()
  .load(SomeClass.class.getClassLoader());

您可以通过反射或实现 setter 接口来设置上述字段,例如:

interface HandlerSetter {
  InvocationHandler getHandler();
  void setHandler(InvocationHandler handler);
}

Class<? extends SomeClass> proxy = new ByteBuddy()
  .subclass(SomeClass.class)
  .defineField("handler", InvocationHandler.class, Visibility.PUBLIC)
  .implement(HandlerSetter.class)
  .intercept(FieldAccessor.ofField("handler"))
  .method(ElementMatchers.any())
  .intercept(InvocationHandlerAdapter.toField("handler"))
  .make()
  .load(SomeClass.class.getClassLoader());

您现在可以实例化该类并将该类转换为用于设置处理程序的接口。

除了 之外InvocationHandler,还有许多其他方法可以创建代理。一种方法是使用MethodDelegation更灵活、通常更快并允许您按需调用超级方法的方法。转发工具也可以使用一个MethodCall或一个Forwarding工具来应用。您可以在相应的类 javadoc 中找到详细信息。

于 2016-10-28T08:24:52.300 回答