在开发具有某些性能要求的Java EE应用程序时,必须在每个发行版之前验证是否满足这些要求。 您可能会想到,哈德森的一项工作每天晚上在某些特定的硬件平台上执行一系列测试测量。
您可以检查已实现的时间并将它们与给定的要求进行比较。 如果测量值与要求的偏差太大,则可以中断构建或至少向团队发送电子邮件。
但是,如何测量代码的执行时间呢? 最初的想法可能是在您的代码库中添加数千个时间测量代码。 但这不仅是很多工作,而且还会影响代码的性能,因为现在时间测量也已在生产中执行。 为了摆脱许多插入,您可能需要利用面向方面的框架(AOP),该框架引入了用于在编译时进行时间测量的代码。 使用这种方式,您至少可以拥有两个版本的应用程序:一个有版本,一个没有额外的开销。 要在某些生产站点上衡量性能,仍然需要重新部署代码。 而且,您必须决定要在编译时观察哪些方法。
因此,Java EE提供了一种易于使用的替代方案:拦截器。 这是当时控制模式反转发挥其优势的原因。 当Application Server调用您的bean方法/ Web服务调用时,它很容易拦截这些调用,并为您提供了在每次调用之前和之后添加代码的方式。
这样,使用拦截器就相当容易了。 您可以在目标方法或引用拦截器实现的类中添加注释,也可以使用部署描述符添加拦截器:
@Interceptors(PerformanceInterceptor.class)
public class CustomerService {
...
}
部署描述符中提供的相同信息如下所示:
<interceptor-binding><target-name>myapp.CustomerService</target-name><interceptor-class>myapp.PerformanceInterceptor.class</interceptor-class>
</interceptor-binding>
拦截器本身可以是一个简单的POJO类,其方法带有@AroundInvoke和一个参数:
@AroundInvoke
public Object measureExecutionTime(InvocationContext ctx) throws Exception {long start = System.currentTimeMillis();try {return ctx.proceed();} finally {long time = System.currentTimeMillis() - start;Method method = ctx.getMethod();RingStorage ringStorage = RingStorageFactory.getRingStorage(method);ringStorage.addMeasurement(time);}
}
在try块之前和finally块中,我们添加了用于时间测量的代码。 从上面的代码可以看出,我们还需要一些内存中的位置,可以在其中存储最后的测量值,以便计算例如平均值和与平均值的偏差。 在此示例中,我们有一个简单的环形存储实现,该实现会在一段时间后覆盖旧值。
但是如何将这些价值观暴露给外界? 由于通过JMX接口公开了Application Server的许多其他值,因此我们可以实现一个简单的MXBean接口,如以下代码片段所示:
public interface PerformanceResourceMXBean {long getMeanValue();
}public class RingStorage implements PerformanceResourceMXBean {private String id;public RingStorage(String id) {this.id = id;registerMBean();...}private void registerMBean() {try {ObjectName objectName = new ObjectName("performance" + id + ":type=" + this.getClass().getName());MBeanServer platformMBeanServer = ManagementFactory.getPlatformMBeanServer();try {platformMBeanServer.unregisterMBean(objectName);} catch (Exception e) {}platformMBeanServer.registerMBean(this, objectName);} catch (Exception e) {throw new IllegalStateException("Problem during registration:" + e);}}@Overridepublic long getMeanValue() {...}...
}
现在,我们可以启动jconsole并查询暴露的MXBean的平均值:
编写一个小的JMX客户端应用程序,例如将采样值写入CSV文件,使您以后可以处理这些值并将它们与以后的测量值进行比较。 这为您提供了应用程序性能演变的概述。
结论
通过使用拦截器,可以轻松地通过部署描述符性能评估功能向现有Java EE应用程序动态添加功能。 如果通过JMX公开了测量值,则可以在以后应用这些值的进一步处理。
翻译自: https://www.javacodegeeks.com/2014/09/analysing-the-performance-degradationimprovements-of-a-java-ee-application-with-interceptors.html