Pustike EventBus is a fork of Guava EventBus, which is probably the most commonly known event bus for Java. Most of the documentation here and test cases are from Guava itself.
The Guava Project contains several core libraries and is distributed as a single module that has a size of ~2.2MB (as of v19.0). So an application using only the EventBus will also need to include the full Guava dependency.
Pustike EventBus is an effort to extract only the event bus library from Guava project without any other dependencies. And it also provides few additional features / changes, like:
@Subscribe(threadSafe = true)
instead of @AllowConcurrentEvents
The project is available on GitHub.
An event bus is a library providing publisher/subscriber pattern for loose coupling between components(event senders and receivers), by sending messages to each other indirectly. Some objects register with the bus to be notified when certain events of interest occur. And some publish events on the bus. The bus notifies each of the registrants when the event is published. So the registrant objects and the event-source objects need not know about each other directly. Each may join or depart the bus at any time. Thus it enables central communication between components, simplifies the code and removes direct dependencies.
To create an instance of event bus with a default identifier and using a per thread dispatch queue and a direct executor which publishes events in the same thread:
EventBus bus = new EventBus();
Dispatcher is used for dispatching events to subscribers, providing different event ordering guarantees that make sense for different situations. Please note that the dispatcher controls the order in which events are dispatched, while the executor controls how (i.e. on which thread) the subscriber is actually called when an event is dispatched to it. Two types of dispatchers are supported:
Subscribe to events by registering listeners to the bus. Subscriber methods in a listener should be annotated with @Subscribe
and the method should take only a single parameter, the type of which will be the event to subscribe to. The registry will traverse the listener class hierarchy and add methods from base classes or interfaces that are annotated.
Object listener = new Object() {
@Subscribe
public void onMessageEvent(String message) {
// process the message here...
}
};
bus.register(listener);
Here internally weak references to listener objects are maintained instead of strong references, as in Gauava.
@Subscribe(threadSafe = true)
. It indicates that the bus may invoke this event subscriber simultaneously from multiple threads.Publish events on the bus which dispatches it to all listeners subscribing to this event type. An instance of any class may be published and it will only be dispatched to subscribers for that type.
String messageEvent = "Hello!";
bus.publish(messageEvent);
String
and Integer
type events are published, the subscriber to Comparable
will be called on both the events. This can be used to create more generic listeners listening for a broader range of events and more detailed ones for specific purposes.Listeners can be unregistered from the bus using
bus.unregister(listener);
CustomerEvent
, VendorEvent
, etc, the TypedEvent<Customer>
, TypedEvent<Vendor>
can be used. The context information can be useful in communicating the state of the object, like new TypedEvent<>(customer, "MODIFIED");
@Subscribe
public void onTypedStringEvent(TypedEvent<String> event) {
// event.getSource();// the object of the event.
// event.getType();// the type of the object.
// event.getContext();// the event context if available, can be null.
}
// ... and publish the event as following
bus.publish(new TypedEvent<>("Hello!"));// note that this will not be matched to TypedEvent<Integer> subscriber!
@Subscribe
public void onDeadEvent(DeadEvent deadEvent) {
// deadEvent.getEvent(); // the event that could not be delivered.
}
@Subscribe
public void onException(ExceptionEvent exceptionEvent) {
// process the exception info here...
}
By default, the event bus will use a ConcurrentMap internally to cache Subscriber methods identified on registering listener objects. To use an external cache like Caffeine for loading & storing subscriber methods in a listener class and type hierarchy of event classes, the following approach can be used:
public class CaffeineSubscriberLoader extends DefaultSubscriberLoader {
private final LoadingCache<Class<?>, List<Method>> subscriberMethodCache;
private final LoadingCache<Class<?>, Set<Class<?>>> typeHierarchyCache;
public CaffeineSubscriberLoader() {
this.subscriberMethodCache = Caffeine.newBuilder().weakKeys()
.build(super::findAnnotatedMethodsNotCached);
this.typeHierarchyCache = Caffeine.newBuilder().weakKeys().weakValues()
.build(super::flattenHierarchyNotCached);
}
@Override
public List<Method> findSubscriberMethods(Class<?> clazz) {
return subscriberMethodCache.get(clazz);
}
@Override
public Set<Class<?>> flattenHierarchy(Class<?> clazz) {
return typeHierarchyCache.get(clazz);
}
@Override
public void invalidateAll() {
subscribeMethodsCache.invalidateAll();
typeHierarchyCache.invalidateAll();
}
}
// and create the event bus using this cache
CaffeineSubscriberLoader subscriberLoader = new CaffeineSubscriberLoader();
Executor executor = Runnable::run; // a simple direct executor!
EventBus eventBus = new EventBus("default", Dispatcher.perThreadDispatchQueue(),
executor, subscriberLoader);
Guava EventBus allows publish-subscribe-style event communication
Square’s Otto: An enhanced event bus with emphasis on Android support.
GreenRobot Event Bus: Android optimized event bus that simplifies communication between Activities, Fragments, Threads, Services, etc. Less code, better quality.
MBassador is a light-weight, high-performance message (event) bus implementation based on the publish subscribe pattern.
Mycila PubSub is a new powerful event framework for in-memory event management.
Spring Framework Application Event publishing support using spring context.
This library is published under the Apache License, Version 2.0
Copyright (C) 2016 the original author or authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.