0

我们正在寻找一种以高性能方式跟踪客户端 POJO 实例状态的解决方案。我们期望的是:每次对 POJO 进行更改时,都会使用 setter 来创建此状态。我们创建了一个基于 OGNL 的监视/事件总线,当进行更改时,我们将正确地发送OgnlChangeEvent到我们的事件总线。

到目前为止,我们研究了 AspectJ / cglib / object graph Diff 解决方案,但它们都占用了太多的 CPU 时间。我们当前的解决方案基于 Spring ,每次调用 Getter 方法时都会MethodInterceptor创建一个新实例。Proxy

在这一点上,我们开始研究代码生成解决方案,我们偶然发现了 Byte Buddy。这个方向是正确的方法吗?我们能否生成一个新Class的扩展我们的客户端 POJO 状态并通知它的 OGNL 前缀,直到调用 setter 方法?

4

2 回答 2

2

Byte Buddy 是一个代码生成工具,当然可以实现这样的解决方案。要创建一个拦截 setter 的类,您可以编写如下代码:

new ByteBuddy()
  .subclass(UserPojo.class)
  .method(ElementMatchers.isSetter())
  .intercept(MethodDelegation.to(MyInterceptor.class)
             .andThen(SuperMethodCall.INSTANCE)
  .make();

你会在哪里编写这样的拦截器:

public class MyInterceptor {
  public static void intercept(Object value) {
    // business logic comes here
  }
}

这样,您可以在每次调用在原始代码之前触发的 setter 时添加一些代码。您还可以使用所有原始类型重载拦截方法,以避免参数装箱。Byte Buddy 弄清楚该为您做什么。

但是,我对您所说的performant感到困惑。上面的代码对我来说与创建一个类相同:

class UserClass {
  String value;
  void setValue(String value) {
    this.value = value;
  }
}

class InstrumentedUserClass extends UserClass {
  @Override
  void setValue(String value) {
    MyInterceptor.intercept(value);
    super.setValue(value);
  }
}

性能主要受您在该intercept方法中执行的操作的性能影响。

最后,我不明白 cglib 如何不适合您,但使用 Spring(构建在 cglib 之上)确实有效。我怀疑你的拦截逻辑有问题,你应该调查一下。

于 2016-03-20T10:02:20.413 回答
1

我认为性能很大程度上取决于您使用的字节码检测框架,而是取决于您在方法拦截器中所做的事情。最后你只会知道你是否测量。

我对您的用例了解不多,但总的来说我会问自己:

  • 我真正需要什么信息?
  • 从中获取信息的基本数据是什么?

您应该将基本数据收集与该数据(信息)的解释分开。通常解释需要更多时间。基础数据是不能从其他数据中推导出来的数据。例如,生日是基本数据,而年龄是从生日得出的。

在方法拦截器中,我会

  • 只收集类名、方法名和参数等基本数据。
  • 将此信息发送到某种工作队列
  • 让后台工作人员生成信息,记录或保留它。

后台工作人员可以例如解释方法名称以查明它是否是属性访问器。通常,您使用从Introspector或至少反射 api获得的BeanInfo来执行此操作。

于 2016-03-20T10:35:23.713 回答