|
21 | 21 |
|
22 | 22 | import org.jspecify.annotations.Nullable; |
23 | 23 |
|
| 24 | +import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler; |
| 25 | +import org.springframework.beans.BeansException; |
24 | 26 | import org.springframework.beans.factory.BeanFactory; |
25 | 27 | import org.springframework.beans.factory.ObjectProvider; |
26 | 28 | import org.springframework.beans.factory.config.BeanFactoryPostProcessor; |
| 29 | +import org.springframework.beans.factory.config.BeanPostProcessor; |
27 | 30 | import org.springframework.boot.autoconfigure.condition.AnyNestedCondition; |
| 31 | +import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; |
28 | 32 | import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; |
29 | 33 | import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; |
30 | 34 | import org.springframework.boot.autoconfigure.condition.ConditionalOnThreading; |
@@ -66,7 +70,7 @@ class TaskExecutorConfigurations { |
66 | 70 |
|
67 | 71 | @Configuration(proxyBeanMethods = false) |
68 | 72 | @Conditional(OnExecutorCondition.class) |
69 | | - @Import(AsyncConfigurerConfiguration.class) |
| 73 | + @Import({ AsyncConfigurerWrapperConfiguration.class, AsyncConfigurerConfiguration.class }) |
70 | 74 | static class TaskExecutorConfiguration { |
71 | 75 |
|
72 | 76 | @Bean(TaskExecutionAutoConfiguration.APPLICATION_TASK_EXECUTOR_BEAN_NAME) |
@@ -161,23 +165,37 @@ private SimpleAsyncTaskExecutorBuilder builder() { |
161 | 165 | } |
162 | 166 |
|
163 | 167 | @Configuration(proxyBeanMethods = false) |
164 | | - @ConditionalOnMissingBean(AsyncConfigurer.class) |
165 | | - static class AsyncConfigurerConfiguration { |
| 168 | + @ConditionalOnBean(AsyncConfigurer.class) |
| 169 | + static class AsyncConfigurerWrapperConfiguration { |
166 | 170 |
|
167 | 171 | @Bean |
168 | | - @ConditionalOnMissingBean |
169 | | - AsyncConfigurer applicationTaskExecutorAsyncConfigurer(BeanFactory beanFactory) { |
170 | | - return new AsyncConfigurer() { |
| 172 | + static BeanPostProcessor applicationTaskExecutorAsyncConfigurerBeanPostProcessor( |
| 173 | + ObjectProvider<BeanFactory> beanFactory) { |
| 174 | + return new BeanPostProcessor() { |
171 | 175 | @Override |
172 | | - public Executor getAsyncExecutor() { |
173 | | - return beanFactory.getBean(TaskExecutionAutoConfiguration.APPLICATION_TASK_EXECUTOR_BEAN_NAME, |
174 | | - Executor.class); |
| 176 | + public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { |
| 177 | + if (bean instanceof AsyncConfigurer asyncConfigurer |
| 178 | + && !(bean instanceof ApplicationTaskExecutorAsyncConfigurer)) { |
| 179 | + return new ApplicationTaskExecutorAsyncConfigurer(beanFactory.getObject(), asyncConfigurer); |
| 180 | + } |
| 181 | + return bean; |
175 | 182 | } |
176 | 183 | }; |
177 | 184 | } |
178 | 185 |
|
179 | 186 | } |
180 | 187 |
|
| 188 | + @Configuration(proxyBeanMethods = false) |
| 189 | + @ConditionalOnMissingBean(AsyncConfigurer.class) |
| 190 | + static class AsyncConfigurerConfiguration { |
| 191 | + |
| 192 | + @Bean |
| 193 | + ApplicationTaskExecutorAsyncConfigurer applicationTaskExecutorAsyncConfigurer(BeanFactory beanFactory) { |
| 194 | + return new ApplicationTaskExecutorAsyncConfigurer(beanFactory, null); |
| 195 | + } |
| 196 | + |
| 197 | + } |
| 198 | + |
181 | 199 | @Configuration(proxyBeanMethods = false) |
182 | 200 | static class BootstrapExecutorConfiguration { |
183 | 201 |
|
@@ -215,4 +233,39 @@ private static final class ModelCondition { |
215 | 233 |
|
216 | 234 | } |
217 | 235 |
|
| 236 | + /** |
| 237 | + * {@link AsyncConfigurer} implementation that delegates to the user-defined |
| 238 | + * {@link AsyncConfigurer} instance, if any. Consistently use the executor named |
| 239 | + * {@value TaskExecutionAutoConfiguration#APPLICATION_TASK_EXECUTOR_BEAN_NAME} in the |
| 240 | + * absence of a custom executor. |
| 241 | + */ |
| 242 | + static class ApplicationTaskExecutorAsyncConfigurer implements AsyncConfigurer { |
| 243 | + |
| 244 | + private final BeanFactory beanFactory; |
| 245 | + |
| 246 | + private final @Nullable AsyncConfigurer delegate; |
| 247 | + |
| 248 | + ApplicationTaskExecutorAsyncConfigurer(BeanFactory beanFactory, @Nullable AsyncConfigurer delegate) { |
| 249 | + this.beanFactory = beanFactory; |
| 250 | + this.delegate = delegate; |
| 251 | + } |
| 252 | + |
| 253 | + @Override |
| 254 | + public Executor getAsyncExecutor() { |
| 255 | + Executor executor = (this.delegate != null) ? this.delegate.getAsyncExecutor() : null; |
| 256 | + return (executor != null) ? executor : getApplicationTaskExecutor(); |
| 257 | + } |
| 258 | + |
| 259 | + @Override |
| 260 | + public @Nullable AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() { |
| 261 | + return (this.delegate != null) ? this.delegate.getAsyncUncaughtExceptionHandler() : null; |
| 262 | + } |
| 263 | + |
| 264 | + private Executor getApplicationTaskExecutor() { |
| 265 | + return this.beanFactory.getBean(TaskExecutionAutoConfiguration.APPLICATION_TASK_EXECUTOR_BEAN_NAME, |
| 266 | + Executor.class); |
| 267 | + } |
| 268 | + |
| 269 | + } |
| 270 | + |
218 | 271 | } |
0 commit comments