Bug Description
WebSocketMessagingAutoConfiguration is using an existing registered Executor bean as the output from bean factory methods AbstractMessageBrokerConfiguration#clientInboundChannelExecutor and AbstractMessageBrokerConfiguration#clientOutboundChannelExecutor which are annotated with @Bean.
This causes the existing registered executor bean to go through the standard bean lifecycle interfaces multiple times. In addition the AbstractMessageBrokerConfiguration is also modifying the bean depending on the executor implementation.
In the case of ThreadPoolTaskExecutor it has several lifecycle interfaces such as BeanNameAware, InitializingBean, ApplicationContextAware, DisposableBean and ApplicationListener which get called for each registration.
In short registering a single instances of a bean multiple times can lead to unexpected issues and would assume most beans are not designed with this intent. AbstractMessageBrokerConfiguration is expecting separate unregistered Executor instances that it will register as beans.
I tripped over this while trying to debug an issue preventing the our application from shutting down. I first noticed the bean name on the applicationTaskExecutor - ThreadPoolTaskExecutor had a bean name of clientOutboundChannelExecutor set inside the instance. Then I figured out the reason why our app was not shutting down was the destroy method of the executor was being called multiple times due to being registered multiple times in the context.
Replication
https://github.com/emopti-jrufer/spring-boot/tree/executer_bug
See org.springframework.boot.websocket.autoconfigure.servlet.WebSocketMessagingAutoConfigurationTests#bug
Workaround
As a workaround I excluded WebSocketMessagingAutoConfiguration and had to configure the message converters in a separate WebSocketMessageBrokerConfigurer.
Bug Description
WebSocketMessagingAutoConfigurationis using an existing registeredExecutorbean as the output from bean factory methodsAbstractMessageBrokerConfiguration#clientInboundChannelExecutorandAbstractMessageBrokerConfiguration#clientOutboundChannelExecutorwhich are annotated with@Bean.This causes the existing registered executor bean to go through the standard bean lifecycle interfaces multiple times. In addition the
AbstractMessageBrokerConfigurationis also modifying the bean depending on the executor implementation.In the case of
ThreadPoolTaskExecutorit has several lifecycle interfaces such asBeanNameAware, InitializingBean, ApplicationContextAware, DisposableBean and ApplicationListenerwhich get called for each registration.In short registering a single instances of a bean multiple times can lead to unexpected issues and would assume most beans are not designed with this intent.
AbstractMessageBrokerConfigurationis expecting separate unregisteredExecutorinstances that it will register as beans.I tripped over this while trying to debug an issue preventing the our application from shutting down. I first noticed the bean name on the
applicationTaskExecutor-ThreadPoolTaskExecutorhad a bean name ofclientOutboundChannelExecutorset inside the instance. Then I figured out the reason why our app was not shutting down was the destroy method of the executor was being called multiple times due to being registered multiple times in the context.Replication
https://github.com/emopti-jrufer/spring-boot/tree/executer_bug
See org.springframework.boot.websocket.autoconfigure.servlet.WebSocketMessagingAutoConfigurationTests#bug
Workaround
As a workaround I excluded
WebSocketMessagingAutoConfigurationand had to configure the message converters in a separateWebSocketMessageBrokerConfigurer.