如何使用代码生成跟踪POJO的状态

时间:2016-03-19 16:22:50

标签: java spring aspectj cglib byte-buddy

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

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

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

2 个答案:

答案 0 :(得分: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之上构建 - 确实有效。我怀疑你应该调查你的拦截逻辑有一些问题。

答案 1 :(得分:1)

我认为性能并不依赖于您使用的字节码检测框架,而是取决于您在方法拦截器中执行的操作。最后你只知道你是否测量。

我对你的用例一无所知,但总的来说我会问自己:

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

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

在方法拦截器中我会

  • 仅收集类名,方法名和参数等基本数据。
  • 将此信息发送给某种工作人员队列
  • 让后台工作人员生成信息,记录或持久化。

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