如何在Java中实现包装装饰器? [英] How to implement a wrapper decorator in Java?

查看:408
本文介绍了如何在Java中实现包装装饰器?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

问题是要创建现有对象的动态增强版本。

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

我无法修改对象的 。相反,我必须:

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


  • 子类

  • 将现有对象包装在新的<$ c中$ c>类

  • 委托对包装对象的所有原始方法调用

  • 实现由另一个界面

  • 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);

}

使用 Byte Buddy 我设法子类化并实现我的界面。问题是委托给包装对象。我发现这样做的唯一方法是使用反射太慢(我对应用程序负载很重,性能很关键)。

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<N>) proxyType;
EnhancedNode enhancedNode = (EnhancedNode) enhancedClass.newInstance();
enhancedNode.setNode(node);

其中节点是子类的对象/包裹。 NodeInterceptor 将调用的方法转发到 getNode 属性。

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

这里是 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;
  }
}

一切正常但拦截方法太慢,我打算直接使用ASM来添加Node的每个方法的实现,但我希望有一个更简单的方法使用Byte Buddy。

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.

推荐答案

您可能希望使用 Pipe 而不是反射API:

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

public class NodeInterceptor {

  @RuntimeType
  public static Object intercept(@Pipe Function<Node, Object> pipe,
                                 @FieldValue("node") Node proxy) throws Exception {
      return proxy != null
        ? pipe.apply(proxy);
        : null;
  }
}

为了使用烟斗,首先需要安装它。如果您有Java 8可用,则可以使用 java.util.Function 。否则,只需定义一些类型:

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<T, S> { 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));

您是否确定反射部分是应用程序性能问题的关键点?您是否正确缓存生成的类并且缓存是否有效?反射API比它的声誉更快,特别是因为使用Byte Buddy倾向于暗示单态呼叫站点。

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())

多次。这没有效果。此外, method.getDeclaringClass()。cast(node)不是必需的。反射API会为你做演员。

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

这篇关于如何在Java中实现包装装饰器?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆