Last week we released Apache Shiro 1.3, and I shared a tutorial on the new Hazelcast support. Today, I’d like to introduce you to the new EventBus system and show you a couple different ways to use it. Shiro’s EventBus is implemented very similar to Guava’s EventBus, if you are already familiar with that, you already know how to use it.

EventBus in Apache Shiro

Apache ShiroAn event bus allows for further decoupling of components when compared to the observable pattern. It differs in that it shifts the notification of event listeners from the observable object itself to the EventBus. We can use the common task of ordering pizza as an example. For the observable pattern, assume I am the observable, as I tend to get stuck with ordering the pizza. In this case each person in my group (the observers) comes directly to me and ‘registers’ by chipping in a few dollars.

In this case I am the PizzaObservable:

And all my friends are a PizzaObserver:

Eventually the pizza shows up, and I notify all of the PizzaObserver‘s directly via the pizzaIsReady() method.

For the EventBus, we will stretch our analogy a bit and say the pizza is for a meetup event. The event participants don’t care who puts in the order or how the pizza is delivered (just that it is free!). With a single @Subscribe annotation we can model the interaction:

When an event coordinator, a sponsor, or a delivery person puts pizza on the table, everyone will be notified.

Each Participant stills needs to register with the event bus, so the full example would look something like this:

In the snippet above the MeetupCoordinator implements EventBusAware which has a single method setEventBus(). It is important to note that the publisher and the subscriber must be using the same EventBus instance. Shiro handles this and all of the boilerplate for any objects configured in your shiro.ini file.  The configuration ends up looking like:

Which just leaves us with a single line of code:

Any objects that publish events just need to implement the EventBusAware interface to get access to the shared EventBus instance. Objects that listen for events simply annotates a method with @Subscribe, this method must only contain a single parameter of the event type you are listening for.

Further, your @Subscribe methods will be called for any event that is an instance of the parameter, which means you can listen for a specific type of event or a range of event types (all extending a common parent).

For our example, we can introduce Jack who is a vegetarian.

And change our putPizzaOnTable method to something like:

Both of these events extend from PizzaAvailableEvent, so Joe and Jill would be notified of any pizza and Jack only the vegetable.

The above code examples and a few additional ones are available on Github.

Enough with the Pizza Analogy

If you are still with me, the three things you need to remember are: implement EventBusAware to get access to the EventBus, use EventBus.publish() to fire an event, and use the @Subscribe annotation for listening to events.

Already using a different event bus in your application?  Take a look at this example which subscribes to all Shiro events, and republishes them to a Guava EventBus.

As of Shiro 1.3.0, SecurityManager and SessionManager implementations are already EventBusAware. The events published out of the box are all related to the various life cycles of the java beans defined a shiro.ini file, for more information checkout the Shiro documentation for Bean Events:
Instantiated Bean Events
Configured Bean Events
Initialized Bean Events
Destroyed Bean Events