Guava EventBus integration

Integrates Guava EventBus with guice.

Features:

  • EventBus available for injection (to publish events)
  • Automatic registration of listener methods (annotated with @Subscribe)
  • Console reporting of registered listeners

Setup

JCenter Maven Central

Remove version in dependency declaration below if you using the BOM extensions.

Maven:

<dependency>
  <groupId>ru.vyarus.guicey</groupId>
  <artifactId>guicey-eventbus</artifactId>
  <version>5.3.0-1</version>
</dependency>

Gradle:

implementation 'ru.vyarus.guicey:guicey-eventbus:5.3.0-1'

See the most recent version in the badge above.

Usage

Register bundle:

GuiceBundle.builder()        
        .bundles(new EventBusBundle())
        ...

Create event:

public class MyEvent {
    // some state
}

Inject EventBus to publish new events.

public class SomeService {
    @Inject
    private EventBus eventbus;    

    public void inSomeMethod() {
        evetbus.post(new MyEvent());
    }
}

Listen for event:

public class SomeOtherService {

    @Subscribe
    public void onEvent(MyEvent event) {
         // handle event   
    }
}

After server start you should see all registered event listeners in the log:

INFO  [2016-12-01 12:31:02,819] ru.vyarus.guicey.eventbus.report.EventsReporter: EventBus subscribers = 

    MyEvent
        com.foo.something.SomeOtherService        

Note

Only subscriptions of beans registered at the time of injector startup will be shown. For example, if MyBean has a subscription method but a binding for it is not declared (and noone depends on it), a JIT binding will be created later in time (when bean will be actually used) and will not be reflected in the logs.

Consuming multiple events

Note that you can build event hierarchies and subscribe to some base event to receive any derived event.

To receive all events use:

@Subscribe
public void onEvent(Object event){    
}

Event bus

By default, events will be handled synchronously (bus.push() waits while all subscribers process).

If you want events to be async use custom eventbus:

new EventBusBundle(
        new AsyncEventBus(someExecutor)
)

By default, event listeners are not considered thread safe and no parallel events processing (for single method) will be performed. To mark subscriber as thread safe use @AllowConcurrentEvents:

@Subscribe
@AllowConcurrentEvents
public void onEvent(MyEvent event)      

If a listener method fails to process an event (throws an exception), then other listeners will still be processed and the exception will be logged. If you want to change this behaviour, set a custom exception handler by creating a custom eventbus instance:

new EventBusBundle(
        new EventBus(customExceptionHandler)
)

Listeners recognition

The guice type listener is used to intercept all bean instances and thus looks at every method in the class hierarchy; however, only beans that actually have @Subscribers will be registered with the event bus. This process is fast and usually causes no issues. If needed, you can reduce the scope with a custom class matcher:

new EventBusBundle()
    .withMatcher(Matchers.inSubpackage("some.package"))

If you want maximum performance, then you can add a marker annotation (e.g. @HasEvents) and reduce scope to just annotated classes:

new EventBusBundle()
    .withMatcher(Matchers.annotatedWith(HasEvents.class))

Console reporting

You can switch off console reporting (for example, if you have too many listeners):

new EventBusBundle().noReport()

Note

Reporting has to use reflection to get subscribers list. If this fails with a newer guava version (not yet supported), then simply disable reporting and everything will work as expected.

Subscribers info bean

EventSubscribersInfo is a registered (available for injection) bean that provides active listeners and used event types. As described above, it uses reflection internally to access the eventbus listeners map. It may be useful for testing.