This post shows how to implement the Observer Design Pattern using the facilities available from Spring Application Events. More importantly, it shows how to publish and consume custom application events in Spring Boot.
Observer Design Pattern – Publish And Consume Events
Here is a short video that describes the Observer Design Pattern
Codes To Publish And Consume Custom Events
Let us create a new Spring Boot Application using IntelliJ (optional) and Spring Initialzr. All in all, we will use these classes and interfaces from Spring Boot.
- org.springframework.context.ApplicationListener
- org.springframework.context.ApplicationEventPublisherAware
- org.springframework.context.ApplicationEvent
First, we create a new project. Choose Spring Initialzr. Then click Next.
Then, provide project information on the next screen.
Next, skip the screen for dependencies.
Then, save the new project to some location.
Next, we create a custom event class. This is the event type that gets published and consumed by our codes.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | package com.turreta.springevent.events; import org.springframework.context.ApplicationEvent; public class AppEventA extends ApplicationEvent { /** * Create a custom application event * * @param source the object on which the event occurred */ public AppEventA(Object source) { super(source); } } |
Then, we create an event publisher.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | package com.turreta.springevent.events; import org.springframework.context.ApplicationEventPublisher; import org.springframework.context.ApplicationEventPublisherAware; import org.springframework.stereotype.Component; @Component public class AppEventAPublisher implements ApplicationEventPublisherAware { private ApplicationEventPublisher publisher; @Override public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) { this.publisher = applicationEventPublisher; } public void publish(AppEventA appEventA) { this.publisher.publishEvent(appEventA); } } |
After that, we create an event source class.
1 2 3 4 5 6 7 8 9 10 | package com.turreta.springevent; public class EventSource { private String notes = "This is the source object for the custom application event.\nIt can be anything actually."; public String getNotes() { return notes; } } |
Finally, we create an event handler. This represents our observer who handles the event. It basically waits for an event “sent” by the publisher. It is possible to have multiple observers by creating a similar class that implements the same interface.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | package com.turreta.springevent.events; import com.turreta.springevent.EventSource; import org.springframework.context.ApplicationListener; import org.springframework.stereotype.Component; @Component public class AppEventAHandler implements ApplicationListener<AppEventA> { @Override public void onApplicationEvent(AppEventA event) { Object source = event.getSource(); if(source instanceof EventSource) { EventSource es = (EventSource)source; System.out.print(es.getNotes()); } } } |
Spring Boot Main class
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | package com.turreta.springevent; import com.turreta.springevent.events.AppEventA; import com.turreta.springevent.events.AppEventAPublisher; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.ApplicationContext; import java.util.concurrent.TimeUnit; @SpringBootApplication public class ComTurretaSpringeventApplication { public static void main(String[] args) throws Exception{ ApplicationContext context = SpringApplication.run(ComTurretaSpringeventApplication.class, args); /** * Alternatively, you can used @Autowired but we are using static main method. */ AppEventAPublisher eventAPublisher = (AppEventAPublisher)context.getBean("appEventAPublisher"); eventAPublisher.publish(new AppEventA(new EventSource())); /** * We wait for a minutes before the application terminates. * For web application, you won't need this at all. */ TimeUnit.MINUTES.sleep(1); } } |
When we run our codes, we get the following output showing the codes published and consumed an event in Spring Boot.
Download the Spring Boot codes
The full source codes are available on this link.