Spring – Application events

Learn to use create publisher-subscriber based events in Spring applications. Spring has inbuilt support for creating application events, publish them and then listen to it in event handlers. There are a few simple guidelines to follow to create / listen 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. Why Spring Events

Sometimes in your spring application, you may want to add capability for listening specific application events so that you can process these events as per application logic.

Examples of these events can be when a employee is added/ deleted; or a certain kind of transaction completed or rolled back. You can always write the event processing code as another method within existing application code, BUT then it will be tightly coupled with your existing code and you will not have much handle to change it later (suppose you don’t want to process those events for certain duration).

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

In 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. Listener 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 your spring application.

2. Publish and Listen Spring Application Events

2.1. Create Custom Application Event Class

All event classes must extend the ApplicationEvent class.

public class EmployeeEvent extends ApplicationEvent
{
	private static final long serialVersionUID = 1L;
	
	private String eventType;
	private EmployeeDTO employee;
	
	//Constructor's first parameter must be source
	public EmployeeEvent(Object source, String eventType, EmployeeDTO employee) 
	{
		//Calling this super class constructor is necessary
		super(source);
		this.eventType = eventType;
		this.employee = employee;
	}

	public String getEventType() {
		return eventType;
	}

	public EmployeeDTO getEmployee() {
		return employee;
	}
}

2.2. Publisher – Implement ApplicationEventPublisherAware Interface

Any bean, which implements ApplicationEventPublisherAware interface, can use its publishEvent() method to send event to listeners.

@Service ("employeeManager")
public class EmployeeManagerImpl implements EmployeeManager, ApplicationEventPublisherAware
{
	@Autowired
	private EmployeeDAO dao;
	
	private ApplicationEventPublisher publisher;
	
	//You must override this method; It will give you acces to ApplicationEventPublisher
	public void setApplicationEventPublisher(ApplicationEventPublisher publisher) {
		this.publisher = publisher;
	}
	
	public EmployeeDTO createNewEmployee()
	{
		EmployeeDTO employee =  dao.createNewEmployee();
		
		//publishing the veent here
		publisher.publishEvent(new EmployeeEvent(this, "ADD", employee));
		
		return employee;
	}
}

2.3. Subscriber/Listener – Implement ApplicationListener Interface

For a bean to listen to certain events, it 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 you use generics, Spring will deliver only messages that match the generic type parameter. In this example, I am using generics code to listen only EmployeeEvent.

public class UserEventsProcessor 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
	}
}

2.4. Configure the beans in application context file

<context:component-scan base-package="com.howtodoinjava.demo" />

<bean class="com.howtodoinjava.demo.processors.UserEventsProcessor" />

2.5. Demo

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();
	}
}

Observe the 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 the events now and we can process then the way we want.

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

3. Other class files used in this example

Here EmployeeDTO class looks like this:

public class EmployeeDTO 
{
	private Integer id;
	private String firstName;
	private String lastName;
	private String designation;

	public EmployeeDTO(String designation) 
	{
		this.id = -1;
		this.firstName = "dummy";
		this.lastName = "dummy";
		this.designation = designation;
	}

	public EmployeeDTO() {
		// TODO Auto-generated constructor stub
	}

	//Setters and Getters

	@Override
	public String toString() {
		return "Employee [id=" + id + ", firstName=" + firstName
				+ ", lastName=" + lastName + ", type=" + designation + "]";
	}
}
public interface EmployeeDAO 
{
	public EmployeeDTO createNewEmployee();
}
@Repository ("employeeDao")
public class EmployeeDAOImpl implements EmployeeDAO
{
	public EmployeeDTO createNewEmployee()
	{
		EmployeeDTO e = new EmployeeDTO();
		e.setId(1);
		e.setFirstName("Lokesh");
		e.setLastName("Gupta");
		return e;
	}
	
	public void initBean() {
		System.out.println("Init Bean for : EmployeeDAOImpl");
	}
	
	public void destroyBean() {
		System.out.println("Init Bean for : EmployeeDAOImpl");
	}
}
public interface EmployeeManager 
{
	public EmployeeDTO createNewEmployee();
}

Happy Learning !!

Was this post helpful?

Join 7000+ Fellow Programmers

Subscribe to get new post notifications, industry updates, best practices, and much more. Directly into your inbox, for free.

9 thoughts on “Spring – Application events”

  1. Why do I need to implement

    ApplicationEventPublisherAware

    ?
    It has a setter method

    setApplicationEventPublisher

    . Now if my service implements this interface, how and when is the setter going to get called?

    Reply
    • Ohh.. I forgot to add this class. It is simple spring controller class.

      @Controller (&quot;employeeController&quot;)
      public class EmployeeController 
      {
          @Autowired
          EmployeeManager manager;
           
          public EmployeeDTO createNewEmployee()
          {
              return manager.createNewEmployee();
          }
      }
      
      Reply
    • The publisher and listener should be registered as a bean so that it is managed by the container.
      So @Component is necessary , other wise the listener will not be registered and event listener and wont be triggered for any change in the event it is listening to.

      Reply
  2. Is it really required ?

        public EmployeeDTO(String designation)
        {
            this.id = -1;
            this.firstName = &quot;dummy&quot;;
            this.lastName = &quot;dummy&quot;;
            this.designation = designation;
        }
     

    You should not be hardcoding this way. You must have used copy constructor:

        public EmployeeDTO createNewEmployee()
        {
            EmployeeDTO e = new EmployeeDTO();
            e.setId(1);
            e.setFirstName(&quot;Lokesh&quot;);
            e.setLastName(&quot;Gupta&quot;);
            return e;
        }
     
    Reply
  3. Thanks alot Lokesh…I am too much confused about the EventPublisher in my current project.

    Regards
    Santosh Singh

    Reply

Leave a Comment

HowToDoInJava

A blog about Java and its related technologies, the best practices, algorithms, interview questions, scripting languages, and Python.