@Retention(value=RUNTIME) @Target(value=TYPE) public @interface Listener
Listenable.addListener(Object)
and related APIs.
Note that even if a class is annotated with this
annotation, it still needs method-level annotation (such as CacheStarted
)
to actually receive notifications.
Objects annotated with this annotation - listeners - can be attached to a
running Cache
so users can be notified of Cache
events.
There can be multiple methods that are annotated to receive the same event, and a method may receive
multiple events by using a super type.
TransactionalEvent.getGlobalTransaction()
can be used, along with TransactionCompletedEvent.isTransactionSuccessful()
to record events and later process them once the transaction has been successfully committed. Example 4 demonstrates
this.
The first, non-blocking, is a mode where the listener is notified in the invoking thread. Operations in this mode
should be used when either the listener operation is expected to complete extremely fast or when the operation can be
performed in a non-blocking manner by returning a CompletionStage to delay
the operation until the stage is complete. This mode is the default mode, overrided by the sync()
property. A method is non blocking if it declares that it returns a CompletionStage
or
one of its subtypes. Note that the stage may return a value, but it will be ignored. The user must be very
careful that no blocking or long running operation is done while in a sync listener as it can cause thread
starvation. You should instead use your own thread pool to execute the blocking or long running operation and
return a CompletionStage
signifying when it is complete.
The second, async, is pretty much identical to sync except that the original operation can continue and complete
while the listener is notified in a different thread. Listeners that throw exceptions are always logged and are not
propagated to the user. This mode is enabled when the listener has specified sync
as false and
the return value is always ignored.
Because the key lock is held for the entire execution of sync listeners (until the completion stage is done), sync listeners should be as short as possible. Acquiring additional locks is not recommended, as it could lead to deadlocks.
GlobalConfiguration.listenerThreadPool()
. The
default values can be found in the KnownComponentNames
class.
clustered=true
, receives a subset of events but from any node that
generated the given event, not just the one they were registered on. The events that a clustered listener can receive are:
CacheEntryCreatedEvent
,
CacheEntryModifiedEvent
,
CacheEntryRemovedEvent
and
CacheEntryExpiredEvent
.
For performance reasons, a clustered listener only receives post events.
Annotation | Event | Description |
---|---|---|
CacheStarted |
CacheStartedEvent |
A cache was started |
CacheStopped |
CacheStoppedEvent |
A cache was stopped |
CacheEntryModified |
CacheEntryModifiedEvent |
A cache entry was modified |
CacheEntryCreated |
CacheEntryCreatedEvent |
A cache entry was created |
CacheEntryRemoved |
CacheEntryRemovedEvent |
A cache entry was removed |
CacheEntryExpired |
CacheEntryExpiredEvent |
A cache entry was expired |
CacheEntryVisited |
CacheEntryVisitedEvent |
A cache entry was visited |
CacheEntryLoaded |
CacheEntryLoadedEvent |
A cache entry was loaded |
CacheEntriesEvicted |
CacheEntriesEvictedEvent |
A cache entries were evicted |
CacheEntryActivated |
CacheEntryActivatedEvent |
A cache entry was activated | \
CacheEntryPassivated |
CacheEntryPassivatedEvent |
One or more cache entries were passivated |
ViewChanged |
ViewChangedEvent |
A view change event was detected |
TransactionRegistered |
TransactionRegisteredEvent |
The cache has started to participate in a transaction |
TransactionCompleted |
TransactionCompletedEvent |
The cache has completed its participation in a transaction |
CacheEntryInvalidated |
CacheEntryInvalidatedEvent |
A cache entry was invalidated by a remote cache. Only if cache mode is INVALIDATION_SYNC or INVALIDATION_ASYNC. |
@Listener public class SingleEventListener { @CacheStarted public CompletionStage<Void> doSomething(Event event) { System.out.println("Cache started. Details = " + event); return null; } }
@Listener public class MultipleEventListener { @CacheStarted @CacheStopped public void doSomething(Event event) { if (event.getType() == Event.Type.CACHE_STARTED) System.out.println("Cache started. Details = " + event); else if (event.getType() == Event.Type.CACHE_STOPPED) System.out.println("Cache stopped. Details = " + event); } }
@Listener(sync=false) public class SingleEventListener { @CacheStarted public void handleStart(Event event) { System.out.println("Cache started"); } @CacheStarted @CacheStopped @CacheBlocked @CacheUnblocked @ViewChanged public void logEvent(Event event) { logSystem.logEvent(event.getType()); } }
@Listener public class EventHandler { private ConcurrentMap<GlobalTransaction, Queue<Event>> map = new ConcurrentHashMap<GlobalTransaction, Queue<Event>>(); @TransactionRegistered public CompletionStage<Void> startTransaction(TransactionRegisteredEvent event) { map.put(event.getGlobalTransaction(), new ConcurrentLinkedQueue<Event>()); return null; } @CacheEntryCreated @CacheEntryModified @CacheEntryRemoved public CompletionStage<Void> addEvent(TransactionalEvent event) { map.get(event.getGlobalTransaction()).add(event);' return null; } @TransactionCompleted public CompletionStage<Void> endTransaction(TransactionCompletedEvent event) { Queue<Event> events = map.get(event.getGlobalTransaction()); map.remove(event.getGlobalTransaction()); System.out.println("Ended transaction " + event.getGlobalTransaction().getId()); if(event.isTransactionSuccessful()) { // Lets say we want to remotely log the events for the transaction - if this has an async or non blocking // API you can use that and not block the thread and wait until it returns to complete the Stage. CompletionStage<Void> stage = performRemoteEventUpdateNonBlocking(events); return stage; } else { return null; } } }
CacheStarted
,
CacheStopped
,
CacheEntryModified
,
CacheEntryCreated
,
CacheEntryRemoved
,
CacheEntryExpired
,
CacheEntryVisited
,
CacheEntryLoaded
,
CacheEntriesEvicted
,
CacheEntryActivated
,
CacheEntryPassivated
,
ViewChanged
,
TransactionCompleted
,
TransactionRegistered
,
CacheEntryInvalidated
,
DataRehashed
,
TopologyChanged
,
PartitionStatusChanged
,
PersistenceAvailabilityChanged
Modifier and Type | Optional Element and Description |
---|---|
boolean |
clustered
Defines whether the annotated listener is clustered or not.
|
boolean |
includeCurrentState
If set to true then the entire existing state within the cluster is
evaluated.
|
Listener.Observation |
observation
Returns the type of observation level this listener defines.
|
boolean |
primaryOnly
Specifies whether the event should be fired on the primary data owner of the affected key, or all nodes that see
the update.
|
boolean |
sync
Specifies whether callbacks on any class annotated with this annotation happens synchronously or asynchronously.
|
public abstract boolean sync
Listener
class for more details.
Defaults to true.public abstract boolean primaryOnly
Note that is value is ignored when clustered()
is true.
public abstract boolean clustered
CacheEntryRemoved
,
CacheEntryCreated
,
CacheEntryRemoved
and CacheEntryExpired
events.public abstract boolean includeCurrentState
clustered()
.
If using a distributed clustered cache it is possible to retrieve new events before the initial transfer is completed. This is handled since only new events are queued until the segment it belongs to is completed for iteration. This also will help reduce memory strain since a distributed clustered listener will need to eventually retrieve all values from the cache.
public abstract Listener.Observation observation
Listener.Observation
Copyright © 2021 JBoss by Red Hat. All rights reserved.