EdM*_*elo 3 java proxy bytecode-manipulation byte-buddy jvm-bytecode
在Java中,可以使用实现来创建动态代理InvocationHandler.尽管进行了JVM优化,但使用反射总是会有一些调用方法的开销.
为了尝试解决这个问题,我尝试使用ByteBuddy在运行时创建代理类,但文档在这方面似乎不够清晰.
如何创建一个MethodCallProxy方法以将方法调用转发到某个类实例?
编辑:
为了更好地澄清我的问题,我提供了一个我想要实现的例子:
我正在构建一个RPC系统.在方法调用的每一侧,我都有一个定义契约的接口(当调用者/被调用者都在JVM下运行时).
@Contract
interface ISomeService {
fun someMethod(arg0: String, arg1: SomePojo): PojoResult
}
Run Code Online (Sandbox Code Playgroud)
在调用站点,我注入一个代理,拦截所有方法调用并将它们转发给被调用者.
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>
Run Code Online (Sandbox Code Playgroud)
最后,在被调用者,我有几个处理程序,每个服务方法一个,负责解组调用参数并将它们转发到服务实现.
@Service
class SomeServiceImpl {
fun someMethod(arg0: String, arg1: SomePojo): PojoResult {
// ...
}
}
Run Code Online (Sandbox Code Playgroud)
我可以使用代码生成来解决这个问题,但生成的jar文件会变得非常大.因此,我想创建这些处理程序的通用版本,并在每个实例中附加一个代理,该代理拦截每个方法调用ISomeService并转发它们SomeServiceImpl.
在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());
Run Code Online (Sandbox Code Playgroud)
如果要创建具有委托给不同实例的代理,则还需要定义一个字段.这可以通过以下说明完成:
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());
Run Code Online (Sandbox Code Playgroud)
您可以通过反射或通过实现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());
Run Code Online (Sandbox Code Playgroud)
您现在可以实例化该类并将该类转换为接口以设置处理程序.
除此之外InvocationHandler,还有许多其他方法可以创建代理.一种方法是使用MethodDelegation哪种方式更灵活,通常更快,并允许您按需调用超级方法.也可以使用MethodCall或Forwarding仪器来应用转发insrumentation .您可以在相应的类javadoc中找到详细信息.
| 归档时间: |
|
| 查看次数: |
2842 次 |
| 最近记录: |