Sometimes we want beans to be able to communicate among
themselves. This is typically done by Sender bean having access to Receiver
bean, and then sender sends a message to receiver by using the reference to the
receiver. This creates a tight coupling between sender and receiver. Sender is
aware of the receiver.
When using IoC POJOs can communicate by interface than by
implementation. This model helps reduce coupling. However it is efficient only
when the sender has to communicate with 1 receiver. When the sender has to
communicate with multiple receivers it has to call the receivers 1 by 1.
In Spring 1 component can send a message to another component
by publishing an event without knowing who the receiver is. Receiver is also
not aware of the sender. Receiver typically listens to an event. It can listen
to multiple events from different senders. In this way, sender and receiver are
loosely coupled.
First you must create an event, by extending
ApplicationEvent class. It is an abstract class to prevent instantiation thus disallowing
clients to create instances of ApplicationEvent class, prohibiting them from
publishing generic event. Spring notifies a listener of all events, so you must
filter the events yourself. If you use generics then Spring delivers the
message to listener that listens specifically that event.
Create and event by extending ApplicationEvent class. Give
it a constructor that accepts an object that describes the event and pass that object
to super class ApplicationEvent. Application class is abstract and does not
have default constructor, so subclasses are forced to provide a 1 or more arg
constructor.
public
class CheckoutEvent extends ApplicationEvent
{
private Date checkoutTime;
public
CheckoutEvent(Object source, Date checkoutTime)
{
super(source);
this.checkoutTime = checkoutTime;
}
//… some more code specific to the event
}
Create an event publisher by implementing ApplicationEventPublisherAware
interface. It is the interface to be implemented by any object that wishes to
be notified of the ApplicationEventPublisher (typically the ApplicationContext)
that it runs in. ApplicationEventPublisher encapsulates the even publishing mechanism.
In the event publisher method just create the event and publish
it by using calling publishEvent(event) on applicationEventPublisher instance.
@Component(value = "checkoutEventPublisher")
public class
CheckoutEventPublisher implements ApplicationEventPublisherAware
{
private
ApplicationEventPublisher applicationEventPublisher;
@Override
public void
setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher)
{
this.applicationEventPublisher = applicationEventPublisher;
}
public void checkout(Object
shoppingCart)
{
System.out.println("Checking out");
CheckoutEvent checkoutEvent = new CheckoutEvent(shoppingCart, new Date());
applicationEventPublisher.publishEvent(checkoutEvent);
}
}
Create a listener
by implementing ApplicationListener interface and overriding
onApplicationEvent(ApplicationEvent) method. Add the code for processing the
event in it.
You must create a bean for the listener, else it won’t be
notified.
Generic listener (Can listen to only 1 event)
As of Spring 3.0, an ApplicationListener can generically declare the event type that it is interested in. When registered with a Spring ApplicationContext, events will be filtered accordingly, with the listener getting invoked for matching event objects only.
@Component
public class
CheckoutEventListener implements
ApplicationListener<CheckoutEvent>
{
@Override
public void
onApplicationEvent(CheckoutEvent checkoutEvent) {
System.out.println("Checkout event occured at " + checkoutEvent.getCheckoutTime());
}
}
Raw listener(Can listen to several events from several
publishers, so you need to check the type of event first before handling it)
@Component
public class
CheckoutEventListener implements ApplicationListener
{
@Override
public void
onApplicationEvent(ApplicationEvent event)
{
if(event instanceof CheckoutEvent)
System.out.println("Checkout
event occured at " + ((CheckoutEvent)event).getCheckoutTime());
}
}