我想在SpringBoot应用程序中引入@Async
方法(用于并行发送邮件)。
但是当我将@EnableAsync
注释放在我们的应用程序的主@Configuration
类(用@SpringBootApplication
注释)时,Flyway数据库迁移在DataSourceInitializer
(运行schema.sql)之前执行。执行我的测试的data.sql。
涉及“应该迁移”的数据库表的第一个操作失败。
删除@EnableAsync
会使一切恢复正常。为什么会发生这种情况?如何解决这个问题(或解决问题)?
更新更多调查结果:@EnableAsync(mode = AdviceMode.ASPECTJ)
保留了数据库设置的原始顺序,但@Async
方法与调用程序线程在同一个线程上运行。我还看到当'{1}}不存在或者使用@EnableAsync
时,Bean'objectPostProcessor'是在早期创建的(第3个bean)。当仅使用@EnableAsync(mode = AdviceMode.ASPECTJ)
时,此bean将在以后创建。
更新2 虽然我无法创建一个可以重现问题的最小项目,但我发现当我注释掉{时,我在受影响的应用程序中恢复了正确的数据库设置顺序{1}}如下:
@EnableAsync
Bean'webSocketConfig'是第一个创建的bean(根据INFO级控制台输出),如果存在@EnableWebSocketMessageBroker
。
答案 0 :(得分:1)
事实证明,我的应用程序中同时存在@EnableAsync
和@EnableWebSocketMessageBroker
会导致所描述的效果。
删除其中一个,恢复了预期的行为,在这种情况下DataSourceInitializerPostProcessor
创建了DataSourceInitializer
,它在飞路迁移发生之前触发了schema.sql和data.sql的执行。
当两个注释都存在时,BeanPostProcessor
internalAsyncAnnotationProcessor
的注册发生在DataSourceInitializerPostProcessor
注册之前。
问题的原因是internalAsyncAnnotationProcessor
的注册导致创建dataSource
bean作为副作用。这种副作用是由Spring寻找TaskExecutor
bean来进行的@Async
方法执行引起的。 spring出乎意料地拿起了因clientInboundChannelExecutor
而出现的@EnableWebSocketMessageBroker
bean。使用此bean导致WebSocketMessagingAutoConfiguration
的实例化,该objectMapper
创建了dataSource
bean(用于json序列化),该bean使用的服务使用依赖于DataSourceInitializerPostProcessor
的DAO存储库。所以这些豆子都被创造了。
由于当时没有注册DataSourceInitializer
,因此在飞路迁移发生后很晚才创建@EnableAsync
。
SimpleAsyncTaskExecutor
的javadoc说明如下:
默认情况下,SimpleAsyncTaskExecutor将用于处理异步方法调用。此外,具有void返回类型的带注释的方法不能将任何异常发送回调用者。默认情况下,仅记录此类未捕获的异常。
我假设,将创建一个@Async
来运行AsyncConfigurer
方法,但是春天会选择一个匹配类型的现有bean。
因此,此问题的解决方案 是实施 Executor
,并提供我自己的@EnableAsync
。这也在//generate hotel table.
$table_hotel = '
//php codes here for generating table
';
:
要自定义所有这些,请实现AsyncConfigurer并提供: *你自己的Executor通过getAsyncExecutor()方法,和 *通过getAsyncUncaughtExceptionHandler()方法自己的AsyncUncaughtExceptionHandler。
通过此调整,数据库设置将再次按预期执行。