【问题标题】:How to track the state of a POJO using code generation如何使用代码生成跟踪 POJO 的状态
【发布时间】:2016-03-20 18:35:23
【问题描述】:

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

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

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

【问题讨论】:

  • 您能否详细说明一些测量的性能问题?您调用了多少次方法,没有更改跟踪的方法执行时间是多少,有更改跟踪的执行时间是多少,以及您在代码的更改跟踪部分中所做的工作概述?
  • 我同意@NándorElődFekete。很难相信 AspectJ 应该比 Spring AOP 慢。如果是这样,您一定是做错了,因为 AspectJ 非常高效。如果我们看到您的方面,也许我们可以提供帮助。但是,如果您对 ByteBuddy 感到满意,那么此评论可能已过时。最近比较忙,没怎么看这里,可能有点晚了。

标签: java spring aspectj cglib byte-buddy


【解决方案1】:

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 想办法为你做点什么。

然而,我对你所说的性能感到困惑。上面的代码在我看来与创建一个类一样:

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 之上)确实有效。我怀疑你的拦截逻辑有问题,你应该调查一下。

【讨论】:

  • 谢谢 :-) CGLIB 正在为我工​​作以及弹簧包装解决方案。主要问题仍然是性能:-(
【解决方案2】:

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

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

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

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

在方法拦截器中我会

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

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

【讨论】:

  • 谢谢勒内!最耗时的部分是为每个 getter 方法创建新的代理,以便继续获取 Ognl 前缀。这就是我寻找字节检测解决方案的原因。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-07-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-08-28
相关资源
最近更新 更多