Trying to enable async event handling combining the @Async
and @EventListener
annotations, but I still see that the listener is running in the publishing thread.
The example you can find here:
@SpringBootApplication @EnableAsync class AsyncEventListenerExample { static final Logger logger = LoggerFactory.getLogger(AsyncEventListenerExample.class); @Bean TaskExecutor taskExecutor() { return new SimpleAsyncTaskExecutor(); } static class MedicalRecordUpdatedEvent { private String id; public MedicalRecordUpdatedEvent(String id) { this.id = id; } @Override public String toString() { return "MedicalRecordUpdatedEvent{" + "id='" + id + '\'' + '}'; } } @Component static class Receiver { @EventListener void handleSync(MedicalRecordUpdatedEvent event) { logger.info("thread '{}' handling '{}' event", Thread.currentThread(), event); } @Async @EventListener void handleAsync(MedicalRecordUpdatedEvent event) { logger.info("thread '{}' handling '{}' event", Thread.currentThread(), event); } } @Component static class Producer { private final ApplicationEventPublisher publisher; public Producer(ApplicationEventPublisher publisher) { this.publisher = publisher; } public void create(String id) { publisher.publishEvent(new MedicalRecordUpdatedEvent(id)); } @Async public void asynMethod() { logger.info("running async method with thread '{}'", Thread.currentThread()); } } }
and my test case:
@RunWith(SpringRunner.class) @SpringBootTest(classes = AsyncEventListenerExample.class) public class AsyncEventListenerExampleTests { @Autowired Producer producer; @Test public void createEvent() throws InterruptedException { producer.create("foo"); //producer.asynMethod(); // A chance to see the logging messages before the JVM exists. Thread.sleep(2000); } }
However in logs I see that both @EventListener
s run in the main
thread.
2016-05-12 08:52:43.184 INFO 18671 --- [ main] c.z.e.async2.AsyncEventListenerExample : thread 'Thread[main,5,main]' handling 'MedicalRecordUpdatedEvent{id='foo'}' event 2016-05-12 08:52:43.186 INFO 18671 --- [ main] c.z.e.async2.AsyncEventListenerExample : thread 'Thread[main,5,main]' handling 'MedicalRecordUpdatedEvent{id='foo'}' event
The async
infrastructure is initialised with @EnableAsync
with an asynchronous TaskExecutor
.
Not sure what I am doing wrong. Could you help?
Thanks.
Using Spring Boot 1.4.2.M2, so Spring 4.3.0.RC1
The @EnableAsync annotation switches on Spring's ability to run @Async methods in a background thread pool. This class also customizes the Executor by defining a new bean. Here, the method is named taskExecutor , since this is the specific method name for which Spring searches.
Spring allows us to create and publish custom events that by default are synchronous. This has a few advantages, such as the listener being able to participate in the publisher's transaction context.
Never use @Async on top of a private method. In runtime, it will not able to create a proxy and, therefore, not work.
Event handling in the ApplicationContext is provided through the ApplicationEvent class and ApplicationListener interface. Hence, if a bean implements the ApplicationListener, then every time an ApplicationEvent gets published to the ApplicationContext, that bean is notified.
There was a regression in Spring Framework 4.3.0.RC1 that leads to that very issue you're having. If you use the SNAPSHOT, your project runs fine.
onTicketUpdatedEvent
runs in also main Thread with Spring Framework 4.2.4 Release as follows. But it runs in SimpleAsyncTaskExecutor if AsyncConfigurer is not implemented.
@EnableAsync(proxyTargetClass = true) @Component @Slf4j public class ExampleEventListener implements AsyncConfigurer { @Async @EventListener public void onTicketUpdatedEvent(TicketEvent ticketEvent) { log.debug("received ticket updated event"); } @Override public Executor getAsyncExecutor() { ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); executor.setMaxPoolSize(100); executor.initialize(); return executor; } @Override public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() { return null; } }
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With