Mastering Spring Boot Event Handling and Asynchronous Processing
Learn how Spring Boot 2.7.16 leverages ApplicationEvent and ApplicationListener for synchronous event handling, then explore two asynchronous approaches—using @Async with @EventListener and custom thread pools with a bespoke ApplicationEventMulticaster—complete with code examples and configuration details.
Environment: SpringBoot 2.7.16
1. Introduction
ApplicationContext event handling uses ApplicationEvent and ApplicationListener. Beans implementing ApplicationListener are notified whenever an ApplicationEvent is published, following the observer pattern.
Since Spring 4.2 the event infrastructure supports annotation‑based listeners and publishing arbitrary objects as events, which are wrapped internally.
1.1 Define an event object
<code>public class PackEvent extends ApplicationEvent {
private static final long serialVersionUID = 1L;
public PackEvent(Object source) {
super(source);
}
}</code>1.2 Define an event listener
<code>@Component
public class PackEventListener implements ApplicationListener<PackEvent> {
@Override
public void onApplicationEvent(PackEvent event) {
System.out.println("触发事件...");
}
}</code>1.3 Publish the event
<code>@Resource
private ApplicationEventMulticaster eventMulticaster;
public void run(ApplicationArguments args) throws Exception {
eventMulticaster.multicastEvent(new PackEvent("自定义Pack"));
}</code>By default the event handling is synchronous, so long‑running tasks should not be placed in listeners. To process events asynchronously there are two main approaches.
2. Asynchronous event handling
2.1 Using @Async
Enable async support and annotate the listener method with @Async.
<code>@EnableAsync
public class AppApplication {}</code> <code>@Async
@EventListener(PackEvent.class)
public void packEventListener(PackEvent event) {
System.out.printf("%s - 事件发生了...%s%n",
Thread.currentThread().getName(), event.getSource());
}</code> <code>task-1 - 事件发生了...自定义Pack</code>2.2 Custom thread pool
Start a new thread inside the listener
<code>@Component
public class PackEventListener implements ApplicationListener<PackEvent> {
@Override
public void onApplicationEvent(PackEvent event) {
new Thread(() -> {
System.out.printf("%s触发事件...%n", Thread.currentThread().getName());
}).start();
}
}</code>Define a custom ApplicationEventMulticaster
<code>@Bean
TaskExecutor taskExecutor() {
ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
taskExecutor.setThreadNamePrefix("pack-event-");
taskExecutor.setCorePoolSize(5);
taskExecutor.setQueueCapacity(100);
taskExecutor.setMaxPoolSize(5);
taskExecutor.initialize();
return taskExecutor;
}
// Bean name must be applicationEventMulticaster
@Bean(name = AbstractApplicationContext.APPLICATION_EVENT_MULTICASTER_BEAN_NAME)
SimpleApplicationEventMulticaster eventMulticaster(BeanFactory beanFactory) {
SimpleApplicationEventMulticaster eventMulticaster =
new SimpleApplicationEventMulticaster(beanFactory);
eventMulticaster.setTaskExecutor(taskExecutor());
return eventMulticaster;
}</code>The core of this mechanism is the initApplicationEventMulticaster() method invoked during AbstractApplicationContext.refresh() , which either retrieves an existing multicaster bean or creates a synchronous one.
All the above constitutes the complete example.
Spring Full-Stack Practical Cases
Full-stack Java development with Vue 2/3 front-end suite; hands-on examples and source code analysis for Spring, Spring Boot 2/3, and Spring Cloud.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.