@Beta public class EventBus extends java.lang.Object
The EventBus allows publish-subscribe-style communication between components without requiring the components to explicitly register with one another (and thus be aware of each other). It is designed exclusively to replace traditional Java in-process event distribution using explicit registration. It is not a general-purpose publish-subscribe system, nor is it intended for interprocess communication.
To receive events, an object should:
Subscribe
annotation;register(Object)
method.
To post an event, simply provide the event object to the
post(Object)
method. The EventBus instance will determine the type
of event and route it to all registered listeners.
Events are routed based on their type — an event will be delivered to any subscriber for any type to which the event is assignable. This includes implemented interfaces, all superclasses, and all interfaces implemented by superclasses.
When post
is called, all registered subscribers for an event are run
in sequence, so subscribers should be reasonably quick. If an event may trigger
an extended process (such as a database load), spawn a thread or queue it for
later. (For a convenient way to do this, use an AsyncEventBus
.)
Event subscriber methods must accept only one argument: the event.
Subscribers should not, in general, throw. If they do, the EventBus will catch and log the exception. This is rarely the right solution for error handling and should not be relied upon; it is intended solely to help find problems during development.
The EventBus guarantees that it will not call a subscriber method from
multiple threads simultaneously, unless the method explicitly allows it by
bearing the AllowConcurrentEvents
annotation. If this annotation is
not present, subscriber methods need not worry about being reentrant, unless
also called from outside the EventBus.
If an event is posted, but no registered subscribers can accept it, it is
considered "dead." To give the system a second chance to handle dead events,
they are wrapped in an instance of DeadEvent
and reposted.
If a subscriber for a supertype of all events (such as Object) is registered,
no event will ever be considered dead, and no DeadEvents will be generated.
Accordingly, while DeadEvent extends Object
, a subscriber registered to
receive any Object will never receive a DeadEvent.
This class is safe for concurrent use.
See the Guava User Guide article on
EventBus
.
Modifier and Type | Class and Description |
---|---|
(package private) static class |
EventBus.EventWithSubscriber
simple struct representing an event and it's subscriber
|
private static class |
EventBus.LoggingSubscriberExceptionHandler
Simple logging handler for subscriber exceptions.
|
Modifier and Type | Field and Description |
---|---|
private java.lang.ThreadLocal<java.util.Queue<EventBus.EventWithSubscriber>> |
eventsToDispatch
queues of events for the current thread to dispatch
|
private SubscriberFindingStrategy |
finder
Strategy for finding subscriber methods in registered objects.
|
private static LoadingCache<java.lang.Class<?>,java.util.Set<java.lang.Class<?>>> |
flattenHierarchyCache
A thread-safe cache for flattenHierarchy().
|
private java.lang.ThreadLocal<java.lang.Boolean> |
isDispatching
true if the current thread is currently dispatching an event
|
private SubscriberExceptionHandler |
subscriberExceptionHandler |
private SetMultimap<java.lang.Class<?>,EventSubscriber> |
subscribersByType
All registered event subscribers, indexed by event type.
|
private java.util.concurrent.locks.ReadWriteLock |
subscribersByTypeLock |
Constructor and Description |
---|
EventBus()
Creates a new EventBus named "default".
|
EventBus(java.lang.String identifier)
Creates a new EventBus with the given
identifier . |
EventBus(SubscriberExceptionHandler subscriberExceptionHandler)
Creates a new EventBus with the given
SubscriberExceptionHandler . |
Modifier and Type | Method and Description |
---|---|
(package private) void |
dispatch(java.lang.Object event,
EventSubscriber wrapper)
Dispatches
event to the subscriber in wrapper . |
(package private) void |
dispatchQueuedEvents()
Drain the queue of events to be dispatched.
|
(package private) void |
enqueueEvent(java.lang.Object event,
EventSubscriber subscriber)
Queue the
event for dispatch during
dispatchQueuedEvents() . |
(package private) java.util.Set<java.lang.Class<?>> |
flattenHierarchy(java.lang.Class<?> concreteClass)
Flattens a class's type hierarchy into a set of Class objects.
|
void |
post(java.lang.Object event)
Posts an event to all registered subscribers.
|
void |
register(java.lang.Object object)
Registers all subscriber methods on
object to receive events. |
void |
unregister(java.lang.Object object)
Unregisters all subscriber methods on a registered
object . |
private static final LoadingCache<java.lang.Class<?>,java.util.Set<java.lang.Class<?>>> flattenHierarchyCache
private final SetMultimap<java.lang.Class<?>,EventSubscriber> subscribersByType
This SetMultimap is NOT safe for concurrent use; all access should be
made after acquiring a read or write lock via subscribersByTypeLock
.
private final java.util.concurrent.locks.ReadWriteLock subscribersByTypeLock
private final SubscriberFindingStrategy finder
AnnotatedSubscriberFinder
is supported, but this is
encapsulated for future expansion.private final java.lang.ThreadLocal<java.util.Queue<EventBus.EventWithSubscriber>> eventsToDispatch
private final java.lang.ThreadLocal<java.lang.Boolean> isDispatching
private SubscriberExceptionHandler subscriberExceptionHandler
public EventBus()
public EventBus(java.lang.String identifier)
identifier
.identifier
- a brief name for this bus, for logging purposes. Should
be a valid Java identifier.public EventBus(SubscriberExceptionHandler subscriberExceptionHandler)
SubscriberExceptionHandler
.subscriberExceptionHandler
- Handler for subscriber exceptions.public void register(java.lang.Object object)
object
to receive events.
Subscriber methods are selected and classified using this EventBus's
SubscriberFindingStrategy
; the default strategy is the
AnnotatedSubscriberFinder
.object
- object whose subscriber methods should be registered.public void unregister(java.lang.Object object)
object
.object
- object whose subscriber methods should be unregistered.java.lang.IllegalArgumentException
- if the object was not previously registered.public void post(java.lang.Object event)
If no subscribers have been subscribed for event
's class, and
event
is not already a DeadEvent
, it will be wrapped in a
DeadEvent and reposted.
event
- event to post.void enqueueEvent(java.lang.Object event, EventSubscriber subscriber)
event
for dispatch during
dispatchQueuedEvents()
. Events are queued in-order of occurrence
so they can be dispatched in the same order.void dispatchQueuedEvents()
void dispatch(java.lang.Object event, EventSubscriber wrapper)
event
to the subscriber in wrapper
. This method
is an appropriate override point for subclasses that wish to make
event delivery asynchronous.event
- event to dispatch.wrapper
- wrapper that will call the subscriber.java.util.Set<java.lang.Class<?>> flattenHierarchy(java.lang.Class<?> concreteClass)
concreteClass
- class whose type hierarchy will be retrieved.clazz
's complete type hierarchy, flattened and uniqued.