如何使用 ByteBuddy 获取 class 的动态代理
How to get a dynamic proxy for a class using ByteBuddy
我想为生成的 classes (Swagger) 使用使用 Proxy.newProxyInstance
的动态代理,这些没有实现接口,这让我想到了 ByteBuddy,它应该允许使用它我来构建 Proxy.newProxyInstance
所需的界面。
我到目前为止:
Class<?> restClass = RestServiceApi.class;
Builder<?> builder = byteBuddy.makeInterface().merge(Visibility.PUBLIC).name(restClass.getName() + "I");
for (Method method : restClass.getMethods()) {
builder = builder.defineMethod(method.getName(),
HOW_TO_DO_THIS);
}
Class<?> restInterface = builder.make().load(this.getClass().getClassLoader()).getLoaded();
Class<?>[] proxyInterfaces = new Class<?>[] { restInterface };
// TODO create manipulatedRestServiceApiThatImplementsRestInterfaceI
asyncServiceProxy = new AsynchronousServiceProxy<>(RestServiceApi.class, errorHandler, guiBlockingListener);
ctrAsyncService = (manipulatedRestServiceApiThatImplementsRestInterfaceI) Proxy.newProxyInstance(RestServiceApi.class.getClassLoader(), proxyInterfaces, asyncServiceProxy);
即使可以弄清楚如何编写定义每个方法所需的代码,我也觉得我没有以正确的方式进行,我将编写大量代码将 Method
的反射信息转换为 ByteBudd 所需的任何代码,我怀疑有更简单的方法来构建此接口 class.
如果有人能指出正确的方向,我将不胜感激。
您可以简单地申请:
builder = builder.define(method).intercept(MethodDelegation.to(YourDelegation.class));
MethodDelegation
在 Javadoc 中有非常广泛的记录,您可能需要通过它的签名解析调用的方法,然后使用反射调用它,以获得最简单的解决方案。
事实证明我的预感是正确的(我从错误的角度出发)并且应该更广泛地提出这个问题。我真正需要的(但没有问到)是一个构建动态代理的解决方案,你没有服务接口但有服务 class。
有了服务接口,可以使用java.lang.reflect.Proxy
搭建动态服务代理:
MyInvocationHandler<ServiceInterface> serviceProxy = new MyInvocationHandler<>();
proxiedService = (ServiceInterface) Proxy.newProxyInstance(ServiceInterface.class.getClassLoader(), new Class[] { ServiceInterface.class }, serviceProxy);
proxiedService.methodOfServiceInterface();
语句 proxiedService.methodOfServiceInterface()
并将调用方法 MyInvocationHandler.invoke(Object proxy, final Method method, final Object[] arguments)
,该方法可以执行实际方法所需的任何操作(例如,通过远程方法调用)。
这种方法可以很好地调用具有接口的 EJB 或 SOAP 服务,但会中断服务 class。所以我真正需要的是一种算法来构建动态服务代理,该代理适用于服务接口 和 服务 classes。
使用 ByteBuddy 构建动态服务代理实际上非常简单。以下通用方法实现了所需的算法:
/**
* Creates a service proxy to call methods of the service class/interface.
*
* @param <T> type of service class or interface
* @param serviceClassOrInterface service class or interface
* @param serviceProxy the service proxy
* @return service proxy
*/
public static <T> T createDynamicProxy(Class<T> serviceClassOrInterface, MyInvocationHandler<T> serviceProxy) {
try {
return new ByteBuddy()
.subclass(serviceClassOrInterface)
.method(isDeclaredBy(serviceClassOrInterface))
.intercept(InvocationHandlerAdapter.of(serviceProxy))
.make()
.load(serviceClassOrInterface.getClassLoader())
.getLoaded().getConstructor().newInstance();
} catch (Exception exception) {
throw new RuntimeException("Error creating dynamic proxy of " + serviceClassOrInterface.getName(), exception);
}
}
可以这样使用:
MyInvocationHandler<ServiceInterface> serviceProxy = new MyInvocationHandler<>();
proxiedService = createDynamicProxy(serviceInterface, serviceProxy);
我想为生成的 classes (Swagger) 使用使用 Proxy.newProxyInstance
的动态代理,这些没有实现接口,这让我想到了 ByteBuddy,它应该允许使用它我来构建 Proxy.newProxyInstance
所需的界面。
我到目前为止:
Class<?> restClass = RestServiceApi.class;
Builder<?> builder = byteBuddy.makeInterface().merge(Visibility.PUBLIC).name(restClass.getName() + "I");
for (Method method : restClass.getMethods()) {
builder = builder.defineMethod(method.getName(),
HOW_TO_DO_THIS);
}
Class<?> restInterface = builder.make().load(this.getClass().getClassLoader()).getLoaded();
Class<?>[] proxyInterfaces = new Class<?>[] { restInterface };
// TODO create manipulatedRestServiceApiThatImplementsRestInterfaceI
asyncServiceProxy = new AsynchronousServiceProxy<>(RestServiceApi.class, errorHandler, guiBlockingListener);
ctrAsyncService = (manipulatedRestServiceApiThatImplementsRestInterfaceI) Proxy.newProxyInstance(RestServiceApi.class.getClassLoader(), proxyInterfaces, asyncServiceProxy);
即使可以弄清楚如何编写定义每个方法所需的代码,我也觉得我没有以正确的方式进行,我将编写大量代码将 Method
的反射信息转换为 ByteBudd 所需的任何代码,我怀疑有更简单的方法来构建此接口 class.
如果有人能指出正确的方向,我将不胜感激。
您可以简单地申请:
builder = builder.define(method).intercept(MethodDelegation.to(YourDelegation.class));
MethodDelegation
在 Javadoc 中有非常广泛的记录,您可能需要通过它的签名解析调用的方法,然后使用反射调用它,以获得最简单的解决方案。
事实证明我的预感是正确的(我从错误的角度出发)并且应该更广泛地提出这个问题。我真正需要的(但没有问到)是一个构建动态代理的解决方案,你没有服务接口但有服务 class。
有了服务接口,可以使用java.lang.reflect.Proxy
搭建动态服务代理:
MyInvocationHandler<ServiceInterface> serviceProxy = new MyInvocationHandler<>();
proxiedService = (ServiceInterface) Proxy.newProxyInstance(ServiceInterface.class.getClassLoader(), new Class[] { ServiceInterface.class }, serviceProxy);
proxiedService.methodOfServiceInterface();
语句 proxiedService.methodOfServiceInterface()
并将调用方法 MyInvocationHandler.invoke(Object proxy, final Method method, final Object[] arguments)
,该方法可以执行实际方法所需的任何操作(例如,通过远程方法调用)。
这种方法可以很好地调用具有接口的 EJB 或 SOAP 服务,但会中断服务 class。所以我真正需要的是一种算法来构建动态服务代理,该代理适用于服务接口 和 服务 classes。
使用 ByteBuddy 构建动态服务代理实际上非常简单。以下通用方法实现了所需的算法:
/**
* Creates a service proxy to call methods of the service class/interface.
*
* @param <T> type of service class or interface
* @param serviceClassOrInterface service class or interface
* @param serviceProxy the service proxy
* @return service proxy
*/
public static <T> T createDynamicProxy(Class<T> serviceClassOrInterface, MyInvocationHandler<T> serviceProxy) {
try {
return new ByteBuddy()
.subclass(serviceClassOrInterface)
.method(isDeclaredBy(serviceClassOrInterface))
.intercept(InvocationHandlerAdapter.of(serviceProxy))
.make()
.load(serviceClassOrInterface.getClassLoader())
.getLoaded().getConstructor().newInstance();
} catch (Exception exception) {
throw new RuntimeException("Error creating dynamic proxy of " + serviceClassOrInterface.getName(), exception);
}
}
可以这样使用:
MyInvocationHandler<ServiceInterface> serviceProxy = new MyInvocationHandler<>();
proxiedService = createDynamicProxy(serviceInterface, serviceProxy);