java中装饰器,如何在Java中实现包装装饰器?

The problem is to create a dynamic enhanced version of existing objects.

I cannot modify the object's Class. Instead I have to:

subclass it

wrap the existing object in the new Class

delegate all the original method calls to the wrapped object

implement all methods that are defined by another interface

The interface to add to existing objects is:

public interface EnhancedNode {

Node getNode();

void setNode(Node node);

Set getRules();

void setRules(Set rules);

Map getGroups();

void setGroups(Map groups);

}

With Byte Buddy I managed to subclass and to implement my interface. The problem is the delegation to the wrapped object. The only way to do this that I found is using reflection what is too slow (I have heavy load on the application and performance is critical).

So far my code is:

Class extends Node> proxyType = new ByteBuddy()

.subclass(node.getClass(), ConstructorStrategy.Default.IMITATE_SUPER_TYPE_PUBLIC)

.method(anyOf(finalNode.getClass().getMethods())).intercept(MethodDelegation.to(NodeInterceptor.class))

.defineField("node", Node.class, Visibility.PRIVATE)

.implement(EnhancedNode.class).intercept(FieldAccessor.ofBeanProperty())

.defineField("groups", Map.class, Visibility.PRIVATE)

.implement(EnhancedNode.class).intercept(FieldAccessor.ofBeanProperty())

.defineField("rules", Set.class, Visibility.PRIVATE)

.implement(EnhancedNode.class).intercept(FieldAccessor.ofBeanProperty())

.make()

.load(getClass().getClassLoader(), ClassLoadingStrategy.Default.WRAPPER)

.getLoaded();

enhancedClass = (Class) proxyType;

EnhancedNode enhancedNode = (EnhancedNode) enhancedClass.newInstance();

enhancedNode.setNode(node);

where Node is the object to subclass/wrap. The NodeInterceptor forwards the invoked methods to the getNode property.

Here the code of the NodeInterceptor:

public class NodeInterceptor {

@RuntimeType

public static Object intercept(@Origin Method method,

@This EnhancedNode proxy,

@AllArguments Object[] arguments)

throws Exception {

Node node = proxy.getNode();

Object res;

if (node != null) {

res = method.invoke(method.getDeclaringClass().cast(node), arguments);

} else {

res = null;

}

return res;

}

}

Everything is working but the intercept method is too slow, I'm planning to use ASM directly to add the implementation of every method of Node but I hope there is a simpler way using Byte Buddy.

解决方案

You probably want to use a Pipe rather than the reflection API:

public class NodeInterceptor {

@RuntimeType

public static Object intercept(@Pipe Function pipe,

@FieldValue("node") Node proxy) throws Exception {

return proxy != null

? pipe.apply(proxy);

: null;

}

}

In order to use a pipe, you first need to install it. If you have Java 8 available, you can use java.util.Function. Otherwise, simply define some type:

interface Function { S apply(T t); }

yourself. The name of the type and the method are irrelevant. The install the type:

MethodDelegation.to(NodeInterceptor.class)

.appendParameterBinder(Pipe.Binder.install(Function.class));

Are you however sure that the reflection part is the critical point of your application's performance problems? Are you caching the generated classes correctly and is your cache working efficiently? The reflection API is faster than its reputation, especially since use Byte Buddy tends to imply monomorphic call sites.

Finally, some general feedback. You are calling

.implement(EnhancedNode.class).intercept(FieldAccessor.ofBeanProperty())

multiple times. This has no effect. Also, method.getDeclaringClass().cast(node) is not necessary. The reflection API does the cast for you.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值