2

我想@Async在我的 SpringBoot 应用程序中引入方法(用于并行发送邮件)。但是,当我将@EnableAsync注释放在我们应用程序的主@Configuration类上(用 注释@SpringBootApplication)时,Flyway DB 迁移会在执行之前执行DataSourceInitializer(它为我的测试运行 schema.sql 和 data.sql)。

涉及“应该迁移”的数据库表的第一个操作失败。

删除@EnableAsync使一切恢复正常。为什么会发生这种情况,我该如何解决这个问题(或解决这个问题)?

更新更多发现:@EnableAsync(mode = AdviceMode.ASPECTJ)保持数据库设置的原始顺序,但该@Async方法在与调用者线程相同的线程上运行。我还看到 Bean 'objectPostProcessor' 是在@EnableAsync不存在或@EnableAsync(mode = AdviceMode.ASPECTJ)使用时提前创建的(第 3 个 bean)。当使用 only 时@EnableAsync,这个 bean 会在很久以后创建。

更新 2虽然我还无法创建一个重现问题的最小项目,但当我@EnableWebSocketMessageBroker在以下注释中注释掉时,我发现受影响的应用程序中恢复了正确的数据库设置顺序:

@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer
{ 
  ...
}

如果存在,Bean 'webSocketConfig' 是创建的第一个 bean(根据 INFO 级控制台输出)@EnableWebSocketMessageBroker

4

1 回答 1

1

事实证明,在我的应用程序中同时存在@EnableAsync@EnableWebSocketMessageBroker存在会导致所描述的效果。

删除其中一个,恢复了预期的行为,在这种情况下,在flyway 迁移发生之前,DataSourceInitializerPostProcessor创建了触发 schema.sql 和 data.sql 的执行。DataSourceInitializer

当两个注释都存在时,BeanPostProcessor命名的注册internalAsyncAnnotationProcessor发生在DataSourceInitializerPostProcessor注册之前。

问题的原因是注册beaninternalAsyncAnnotationProcessor导致创建dataSourcebean 作为副作用。这种副作用是由 spring 寻找要TaskExecutor使用的 bean 来@Async执行方法造成的。春天意外地捡起了 clientInboundChannelExecutor因为@EnableWebSocketMessageBroker. 使用这个 bean 会导致WebSocketMessagingAutoConfiguration创建objectMapperbean(用于 json 序列化)的实例化,该 bean 使用使用 DAO 存储库的服务,这些服务依赖于dataSource. 所以所有这些bean都被创建了。

因为DataSourceInitializerPostProcessor当时还没有注册,DataSourceInitializer是在飞行路线迁移发生后很久才创建的。

javadoc for@EnableAsync说明如下:

默认情况下,SimpleAsyncTaskExecutor 将用于处理异步方法调用。此外,具有 void 返回类型的带注释的方法不能将任何异常传输回调用者。默认情况下,仅记录此类未捕获的异常。

我假设SimpleAsyncTaskExecutor将创建 a 来运行这些@Async方法,但是 spring 选择了一个具有匹配类型的现有 bean。

所以这个问题的解决方案是实现 AsyncConfigurer,并提供我自己的Executor. 这在以下的 javadoc 中也有建议@EnableAsync

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

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

于 2016-04-26T07:34:32.043 回答