Spring @EnableAsync打破bean初始化顺序?

时间:2016-04-21 11:29:09

标签: java spring spring-boot flyway spring-async

我想在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

1 个答案:

答案 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 ';

的javadoc中提出
  

要自定义所有这些,请实现AsyncConfigurer并提供:   *你自己的Executor通过getAsyncExecutor()方法,和   *通过getAsyncUncaughtExceptionHandler()方法自己的AsyncUncaughtExceptionHandler。

通过此调整,数据库设置将再次按预期执行。