Spring Application Events

Learn to use create publisher-subscriber based events in a Spring application. Spring has inbuilt support for creating application events, publishing them and then listening to them in event handlers. There are a few simple guidelines to follow to create/listen to application events:

  1. The event should extend ApplicationEvent
  2. The publisher should inject an ApplicationEventPublisher object
  3. The listener should implement the ApplicationListener interface

1. Spring Events

Sometimes in our application, we may want to add the capability for listening to specific application events so that we can process these events for various audit purposes. Examples of these events can be when an employee is added/ deleted, or a certain kind of transaction is completed or rolled back.

We can always write the event processing code as another method within the existing application code, BUT then it will be tightly coupled with your existing code, and we will not have much handle to change it later (suppose you don’t want to process those events for a certain duration).

If you can configure event processors through the application context file, then we need not change your application code as well as the event processor code in most circumstances. Any time we need to switch off event processing or add another event processor for that event, all you need to do is change your context file configuration, and that’s it. Sounds good !!

In the spring event-based communication model, the sender component just publishes an event without knowing who the receiver will be. Actually, there may be more than one receiver component. Also, the receiver needn’t know who is publishing the event. Listeners can listen to multiple events from different senders at the same time. In this way, the sender and receiver components are loosely coupled.

Let’s learn how we can achieve this publish and listen events in a spring application.

2. Publishing Spring Events

2.1. Creating Event Class

Till Spring 4.2, all event classes had to extend the ApplicationEvent class.

public class EmployeeEvent extends ApplicationEvent
{
    private String eventType;
    private EmployeeDTO employee;

    //constructors and getters
}

With later versions of Spring, extending the ApplicationEvent is not mandatory.

public class EmployeeEvent
{
    private String eventType;
    private EmployeeDTO employee;

    //constructors and getters
}

2.2. Event Publisher

To publish the event, the publisher can simply inject the ApplicationEventPublisher and use the publishEvent() API. The publishEvent() API accepts the method argument of type Object so extending the ApplicationEvent class is not necessary anymore.

@Service ("employeeManager")
public class EmployeeManagerImpl implements EmployeeManager
{
	@Autowired
	private EmployeeDAO dao;

	@Autowired
        private ApplicationEventPublisher applicationEventPublisher;

	public EmployeeDTO createNewEmployee()
	{
		EmployeeDTO employee =  dao.createNewEmployee();
		publisher.publishEvent(new EmployeeEvent(this, "ADD", employee));  //publish event
		return employee;
	}
}  

Before Spring 4.2, any bean, which implements ApplicationEventPublisherAware interface, could have used its publishEvent() method to send events to the registered listeners.

@Service ("employeeManager")
public class EmployeeManagerImpl implements EmployeeManager, ApplicationEventPublisherAware
{
	@Autowired
	private EmployeeDAO dao;
	private ApplicationEventPublisher publisher;

	public void setApplicationEventPublisher(ApplicationEventPublisher publisher) {
		this.publisher = publisher;
	}

	public EmployeeDTO createNewEmployee()
	{
		EmployeeDTO employee =  dao.createNewEmployee();
		publisher.publishEvent(new EmployeeEvent(this, "ADD", employee));   //publish event
		return employee;
	}
}

3. Creating Event Listener

3.1. Using ApplicationListener

To listen to certain events, a bean must implement the ApplicationListener interface and handle the events in the onApplicationEvent() method. Actually, Spring will notify a listener of all events, so you must filter the events by yourself.

If we use generics, Spring will deliver only messages that match the generic type parameter. In this example, we are using generics code to listen only EmployeeEvent.

@Component
public class EmployeeEventsProcessor implements ApplicationListener<EmployeeEvent>
{
	public void onApplicationEvent(EmployeeEvent event)
	{
		EmployeeEvent employeeEvent = (EmployeeEvent) event;

		System.out.println("Employee " + employeeEvent.getEventType()
                          + " with details : " + employeeEvent.getEmployee());

		// Do more processing as per application logic
	}
}

3.2. @EventListener Annotation

Since Spring 4.1, we can simply annotate a method with @EventListener and register the event listener of the type method argument.

@Component
public class EmployeeEventsProcessor {

  @EventListener
  void handleEmployeeEvent(EmployeeEvent event) {
    // handle the event
  }
}

Note that event type can be defined in the annotation itself. Also, we can register multiple events to a single method.

@Component
public class EmployeeEventsProcessor {

  @EventListener(EmployeeEvent.class)
  void handleEmployeeEvent() {
    // handle the event
  }

  @EventListener({ApplicationStartEvent.class, ApplicationStopEvent.class})
  void handleApplicationEvent() {
    // handle the event
  }
}

If the event handler method is non-void, Spring will create a new Event for the returned value.

@Component
public class EmployeeEventsProcessor {

  @EventListener(EmployeeEvent.class)
  AuditEvent handleEmployeeEvent() {
    // handle the event
    return new AuditEvent();
  }

  @EventListener(AuditEvent.class)
  void handleAuditEvent() {
    // handle the event
  }
}

4. Demo

In the following example, we are creating an Employee that will trigger the application event.

public class TestSpringContext
{
	@SuppressWarnings("resource")
	public static void main(String[] args) throws Exception
	{
		ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");

		EmployeeController controller = context.getBean(EmployeeController.class);

		controller.createNewEmployee();
	}
}

Program output.

INFO: Loading XML bean definitions from class path resource [applicationContext.xml]
Employee ADD with details : Employee [id=1, firstName=Lokesh, lastName=Gupta, type=null]

Great. We are able to listen to the events now, and we can process them the way we want.

Please note that application context itself also publish container events such as ContextClosedEvent, ContextRefreshedEvent, and RequestHandledEvent. If any of the beans want to be notified of these events, they can implement the ApplicationListener interface.

Happy Learning !!

2 Comments
Newest
Oldest Most Voted
Inline Feedbacks
View all comments

Comments are closed for this article!

About Us

HowToDoInJava provides tutorials and how-to guides on Java and related technologies.

It also shares the best practices, algorithms & solutions and frequently asked interview questions.