2016-03-19 30 views
0

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

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

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

+0

你能详细说明一些测量的性能问题吗?您调用方法的次数,没有更改跟踪的方法执行时间是多少,更改跟踪的执行时间是多少,以及您在代码的更改跟踪部分中执行的操作的概述? –

+0

我同意@NándorElődFekete。很难相信AspectJ应该比Spring AOP慢。如果是这样,你必须做一些错误的事情,因为AspectJ非常高效。如果我们看到你的方面,也许我们可以帮助。但是如果你对ByteBuddy感到满意,也许这个评论已经过时了。我最近在这里没有读过很多东西,因为我很忙,所以我在这里评论有点迟,也许。 – kriegaex

回答

2

Byte Buddy是一个代码生成工具,它当然可以实现这样的解决方案。为了创建一个截取一个二传手的一类,你会写这样的代码:

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 
    } 
} 

这样一来,每次都可以添加一些代码二传手在原始代码之前被触发。您还可以使用所有基元类型重载拦截方法,以避免对参数进行装箱。 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之上 - 是行得通的。我怀疑你应该研究一下你的拦截逻辑有一些问题。

+0

谢谢:-) CGLIB正在为我工​​作,以及春季包装解决方案。主要的问题是,并且仍然是性能:-( –

1

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

我不知道很多关于你的使用情况,但一般我会问自己:

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

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

在方法拦截我会

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

背景工作者可以例如解释方法名称以找出它是否是属性存取器。通常你使用从Introspector或至少反射api得到的BeanInfo来做到这一点。

+0

感谢René!最耗费的部分是为每个getter方法创建新的代理以便继续获得Ognl前缀,这就是为什么我寻找字节检测解决方案的原因。 –