- Java EE 8 High Performance
- Romain Manni Bucau
- 471字
- 2021-06-30 19:14:34
CDI instrumentation
If we focus back on the Metrics library, we will find several CDI integrations. The global idea is to decorate the code with some annotation and automatically get the metrics associated with the executed code. Clearly, it will impact your code this way (using https://github.com/astefanutti/metrics-cdi for instance):
@Transactional
@ApplicationScoped
public class QuoteService {
@PersistenceContext
private EntityManager entityManager;
@Timed(name = "create")
public Quote create(final Quote newQuote) {
entityManager.persist(newQuote);
entityManager.flush();
return newQuote;
}
}
The @Timed annotation will automatically wrap the method execution in a Metrics timer and will therefore provide the statistics about the execution time of the method. The relevant code of the interceptor associated with the @Timed annotation is very close to this logic:
private Object onInvocation(InvocationContext context) throws Exception { Timer.Context time = findTimer(context).time(); try { return context.proceed(); } finally { time.stop(); } }
This is exactly what we want to achieve but it has one trap we didn't think about yet: the exception handling. To understand this point, we can compare the code used in the retired project (called Apache Sirona), which had the following differently implemented feature:
protected Object doInvoke(final InvocationContext context) throws Throwable {
final Context ctx = before(context);
Throwable error = null;
try {
return proceed(context);
} catch (final Throwable t) {
error = t;
throw t;
} finally {
if (error == null) {
ctx.stop();
} else {
ctx.stopWithException(error);
}
}
}
What is important to see here is that the code path changes in the case of an exception. In terms of statistics, this implies that failures will have a different marker from successful calls in the metrics report. This is important to notice because the execution time of a failure is rarely comparable to a success, even for simple methods. Let's take a simple finder example from our quote manager application and observe this. Here is the line we will investigate:
entityManager.find(Quote.class, id)
A normal call with a valid ID will be around 6 to 7 ms (on my reference machine, with my personal configuration). The EntityManager#find method can take any type for the identifier, so if we pass a wrong type (such as String instead of long ) then the call should compile and execute. Eclipselink will complain with an exception but the performance impact is something interesting: 0 ms! Indeed, this example is very extreme and is a bug, but if you have some rate limiting on an endpoint or some sanity checks at the beginning of the methods, the same impact can be observed.
This means that if the framework you are using is putting all the invocations (with errors or not) in the same bucket, you can have a very good performance but a very slow application, since the average of the success/failure makes the figures look good.
- 零起點學Linux系統(tǒng)管理
- 大學計算機應用基礎實踐教程(Windows 7+Office 2013)
- PLC控制系統(tǒng)應用與維護
- 嵌入式Linux驅動程序和系統(tǒng)開發(fā)實例精講
- 移動應用UI設計模式(第2版)
- ElasticSearch Cookbook
- RHCSARHCE 紅帽Linux認證學習指南(第7版)EX200 & EX300
- 分布式高可用架構之道
- iOS 10 開發(fā)指南
- Implementing Domain-Specific Languages with Xtext and Xtend(Second Edition)
- BuddyPress Theme Development
- Getting Started with Citrix XenApp 6.5
- 數(shù)字系統(tǒng)設計與VHDL
- Windows PE權威指南
- Windows XP操作系統(tǒng)5日通