In this post, we will explore the creation of an application event and the process of listening for application events within a Spring Boot application. In Spring Boot, the ApplicationEventPublisher
class is used to publish application events. To listen for and execute these events when they occur, the @EventListener
annotation is used. Furthermore, the application event listener is capable of executing in either synchronous or asynchronous mode, allowing for parallel execution when configured in asynchronous mode. The provided code includes an example demonstrating how to publish an application event and effectively listen for its occurrence.
The event-driven programming paradigm operates akin to the publisher-subscriber model. When an event is published, all subscribers receive and process it. These events can be processed either synchronously or asynchronously. Implementing event-driven programming in a Spring Boot application involves three essential steps.
- The application event
- Event Publisher
- Event Listener
Step 1: Create an Event Class
The event class functions as a Plain Old Java Object (POJO) with properties accompanied by getter and setter methods. It serves as the conduit for transferring data from the event publisher to the event listeners. Any pertinent data that needs to be communicated from a publisher to all event listeners is encapsulated within the event class. Upon the occurrence of an event, the data set within the event class is disseminated to all registered listener classes.
MyEvent.java
package com.test; public class MyEvent { private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } }
Step 2: Create Event Publisher Class
The event publisher class is utilized within the Spring Boot application to broadcast an event. To accomplish this, employ the Spring Boot class ApplicationEventPublisher
. In your publisher class, autowire the ApplicationEventPublisher
class. To publish an event, utilize the publishEvent
API within the ApplicationEventPublisher
class.
Firstly, establish an event class and assign the values intended for transmission to all listeners. Subsequently, pass the event object to the publishEvent
method of the ApplicationEventPublisher
class. This action ensures that the event is disseminated to all registered listener classes.
In the ensuing example, a MyEvent
class object is instantiated and provided with a value. The listener class invokes the publishEvent
method by passing an event object. When the addMyEvent
method is called, the listener generates an event object and publishes it within the context of event-driven programming.
MyPublisher.java
package com.test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationEventPublisher; import org.springframework.stereotype.Component; @Component public class MyPublisher { @Autowired private ApplicationEventPublisher publisher; public void addMyEvent(String name) { System.out.println("PUBLISHER: Starting MyEvent - " + name); MyEvent event = new MyEvent(); event.setName(name); this.publisher.publishEvent(event); System.out.println("PUBLISHER: Starting MyEvent - " + name); } }
Step 3: Create Event Listener Class
The event listener class patiently awaits the occurrence of an event. Upon the event’s initiation, the corresponding listener method within the class is invoked and executed. Each event listener associated with a particular event is summoned in a sequential order, executing one listener at a time. In the event that a listener is configured in asynchronous mode, it runs concurrently, and the publisher doesn’t wait for the listeners’ responses.
A listener class will feature a method designated for listening to events, adorned with the @EventListener
annotation. The event class itself is passed as a parameter to the event listener method. When an event transpires, it is broadcast to all registered event listeners. If a listener method is linked to the triggered event class, the associated event listener method is invoked. Consequently, for the triggered event class, all registered event listener methods are executed sequentially.
In the forthcoming example, a listener class encompasses a listener method with the @EventListener
annotation. The listener method accepts an Event class parameter. When an event of the specified class is triggered, the corresponding listener method is invoked.
MyListener.java
package com.test; import org.springframework.context.event.EventListener; import org.springframework.stereotype.Component; @Component public class MyListener { @EventListener public void handler(MyEvent event) { System.out.println("LISTENER: Name of MyEvent - " + event.getName()); } }
Step 4: Publish an Event
To publish an event in a Spring Boot application, leverage the publish
method. In the provided example, a RESTful web service is established to invoke the publisher method. The REST controller method encompasses an API call to the publisher method. The REST controller class is automatically wired with the publisher class. Consequently, upon calling the REST API, the REST controller utilizes the publisher class to publish the event.
TestController.java
package com.test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; @RestController public class TestController { @Autowired MyPublisher publisher; @GetMapping(value = "/startEvent") public String start(@RequestParam String name) { publisher.addMyEvent(name); return "Event Started"; } }
Step 5: Listening an Event
When the publisher is invoked from the RESTful web service, the listener class is automatically triggered, leading to the execution of the listener method. The publisher method will patiently wait until all listener methods have been successfully executed before returning control to the publisher method.
The console log below illustrates the functioning of the event-driven program within the Spring Boot application. Initially, the publisher’s log is displayed, followed by the invocation of the listener method and the corresponding log. Subsequently, control is transferred back to the publisher, concluding with the printing of the final log in the publisher method.
2023-06-09 23:24:16.316 INFO 7864 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8080 (http) 2023-06-09 23:24:16.344 INFO 7864 --- [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat] 2023-06-09 23:24:16.344 INFO 7864 --- [ main] org.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/9.0.65] 2023-06-09 23:24:16.491 INFO 7864 --- [ main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext 2023-06-09 23:24:16.491 INFO 7864 --- [ main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 1328 ms 2023-06-09 23:24:16.909 INFO 7864 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http) with context path '' 2023-06-09 23:24:16.923 INFO 7864 --- [ main] c.t.SpringBootEventDrivenApplication : Started SpringBootEventDrivenApplication in 2.36 seconds (JVM running for 4.141) 2023-06-09 23:25:10.721 INFO 7864 --- [nio-8080-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring DispatcherServlet 'dispatcherServlet' 2023-06-09 23:25:10.722 INFO 7864 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : Initializing Servlet 'dispatcherServlet' 2023-06-09 23:25:10.722 INFO 7864 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : Completed initialization in 0 ms PUBLISHER: Starting MyEvent - Kim LISTENER: Name of MyEvent - Kim PUBLISHER: Starting MyEvent - Kim