- Java EE 8 High Performance
- Romain Manni Bucau
- 459字
- 2021-06-30 19:14:27
Events
CDI events globally provide an event BUS inside the application. They can be synchronous or asynchronous. To let you have an idea, here is what the code can look like:
@ApplicationScoped
public class LifecycleManager {
@Inject
private Event<Starting> startingEvent;
public void starting() {
final Starting event = new Starting();
startingEvent.fire(event);
startingEvent.fireAsync(event);
}
}
As both types of invocations are exclusive, what we can note here is that these snippets call fire() and fireAsync(). To be able to target all the observers, you need to invoke both. This means that the associated logic will be twice.
Without entering into the details that do not impact our performance, both cases share the same resolution mechanism:
- Resolve the observers based on the event type.
- Remove the observers not matching the fire type (asynchronous or synchronous).
- Sort the observers by priority.
- Handle the invocations.
The difference between synchronous and asynchronous cases is point 4. In the synchronous case, it just means, invoke the observers, whereas in the asynchronous case, it means, call asynchronously and return CompletionStage representing all the invocation results.
The parts impacting the performance are the resolution of the observers and the invocation, which can require some bean resolution.
We already saw bean resolution, so let's dig into the observer resolution here. Indeed, the implementation is specific to the vendor you are using. But, as it is impossible to use static analysis to implement this part, the resolution is done at runtime with a cache per event type. Note that the caching depends a lot on the implementation. Most will only cache raw type events.
This concretely means that the invocation without generics, as shown in the following code, will be way faster than the invocation that implements generics and enforces the CDI container to do some more resolution:
event.fire(new MyEvent());
In terms of the code, and to let you compare it with the previous example, the code with generics would be exactly the same except the event would be parameterized:
event.fire(new MyEvent<String>());
Then, once you have the potential set of observers, you need to reduce the set based on the qualifiers that the caller configures for the event. This also implies some reflection, more or less cached, depending on the implementation.
Finally, some runtime checks are enforced by the set of tests that the vendors have to pass so that we can claim to be compliant with the specifications.
All these steps are more or less optimized by vendors depending on the cases they may have received complaints about. But in all of them, you can end up on code paths where everything is done at runtime for the firing of each event, which can be a pain in terms of the performance.
- Linux系統架構與運維實戰
- Google系統架構解密:構建安全可靠的系統
- Mastering KVM Virtualization
- 玩到極致 iPhone 4S完全攻略
- 嵌入式Linux驅動程序和系統開發實例精講
- Joomla! 3 Template Essentials
- Windows Server 2012網絡操作系統項目教程(第4版)
- Linux內核設計的藝術:圖解Linux操作系統架構設計與實現原理
- Hands-On UX Design for Developers
- 分布式高可用架構之道
- Windows 7使用詳解(修訂版)
- 鴻蒙操作系統設計原理與架構
- Implementing Domain-Specific Languages with Xtext and Xtend(Second Edition)
- Learning Joomla! 3 Extension Development(Third Edition)
- 用“芯”探核:基于龍芯的Linux內核探索解析