Introduction
CDI events are a very handy way of loosely coupling event driven code. At some point in your code you raise the event, and in some other area, you execute some functionality when this event occurs.
And there is no relation or code dependency between the 2 areas except the CDI event payload class.
For example
public class DataUpdatedEvent {
}
@Inject
private Event<DataUpdatedEvent> dataUpdatedEvent;
public void doSomething() {
dataUpdatedEvent.fire(new DataUpdatedEvent());
}
public void onDataUpdate(@Observes DataUpdatedEvent dataUpdatedEvent) {
// React on event
}
Synchronous
By default, the code is executed synchronous. But there are some other use case scenarios already possible without the need for the new, under development, CDI 2.0 spec which will allow also asynchronous execution.
A scenario that I used recently was to have some Cache mechanism available for data stored in a database. I know there are a lot of full blown solutions like Infinispan, EHCache or TerraCotta to name a few. But I wanted to have a simple Map instance which also contains the data from the database table which changes very rarely.
When you place the event fire within a EJB stateless method, you don't have the required behaviour.
@Stateless public class DataBoundary { @PersistenceContext private EntityManager em; @Inject private Event<DataUpdatedEvent> dataUpdatedEvent; public void saveData(Data data) { // Obviously, some more clever things to do em.persist(data); dataUpdatedEvent.fire(new DataUpdatedEvent()); } }
Since the execution of the CDI event mechanism is synchronous, the reading of the database table is done before the new data is committed and thus we are reading the old situation.
@Observer(during)
The Observer annotation has an element called during, which you can use to define when the observer method (the one with the @Observer annotation parameter) is executed.
By default, as already mentioned, it is immediately after the rase of the event. But you can also specify here the value TransactionPhase.AFTER_SUCCESS
public void onDataUpdate(@Observes(during = TransactionPhase.AFTER_SUCCESS) DataUpdatedEvent dataUpdatedEvent) { // Load the cache again }
When the event is fired within a transaction, the observer method is executed after the transaction is committed successful to the database.
That is what we need in our simplistic caching example. The code will run after all the data is in the database table and thus the cache will be using the latest data.
Have fun