2016-04-21 2 views
2

Я хотел ввести методы @Async (для отправки писем параллельно) в моем приложении SpringBoot. Но когда я помещал аннотацию @EnableAsync в основной класс нашего приложения @Configuration (аннотированный @SpringBootApplication), миграция БД Flyway выполняется до выполнения DataSourceInitializer (который запускает schema.sql и data.sql для моих тестов).Spring @EnableAsync нарушает порядок инициализации боба?

Первая операция, связанная с таблицей базы данных «должна быть перенесена», не выполняется.

Снятие @EnableAsync ставит все в норму. Почему это происходит и как я могу исправить это (или решить проблему)?

Update еще несколько выводов: @EnableAsync(mode = AdviceMode.ASPECTJ) сохраняет первоначальный порядок настройки БД, но метод @Async работает на том же потоке, вызывающей нити затем. Я также видел, что Bean «objectPostProcessor» создается раньше (третий компонент), когда @EnableAsync нет, или используется @EnableAsync(mode = AdviceMode.ASPECTJ). Когда используется только @EnableAsync, этот компонент создается намного позже.

Update 2 Хотя я не был в состоянии создать минимальный проект, который воспроизводит эту проблему все же, я выяснил, что собственно DB порядок установки восстанавливается в моем пораженном приложении, когда я закомментируйте @EnableWebSocketMessageBroker в следующем:

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

Bean 'webSocketConfig' является первым боба создана (как на выход консоли INFO-уровень), если @EnableWebSocketMessageBroker присутствует.

+0

У вас есть ошибки с помощью Flyway? Как вы убедитесь, что асинхронный материал по-прежнему работает только после завершения миграции? – Thilo

+0

Пожалуйста, проверьте мое обновление по вопросу. На самом деле миграция, похоже, работает нормально, вся БД воссоздается позже. – sorrymissjackson

+0

Я не понимаю вопроса. Перед попыткой использовать базу данных необходимо запустить код миграции. Почему вы хотите запустить его «асинхронно»? – Thilo

ответ

1

Оказалось, что наличие в моем приложении @EnableAsync и @EnableWebSocketMessageBroker вызвало описанный эффект.

Снятие одного из них, восстановление ожидаемого поведения, и в этом случае DataSourceInitializerPostProcessor создал DataSourceInitializer, который инициировал выполнение schema.sql и data.sql перед миграциями на пролет.

Когда присутствовали оба аннотации, регистрация BeanPostProcessor по имени internalAsyncAnnotationProcessor произошла до регистрации DataSourceInitializerPostProcessor.

Причина, по которой проблема заключалась в том, что регистрация internalAsyncAnnotationProcessor привела к созданию бобов dataSource в качестве побочного эффекта. Этот побочный эффект был вызван весной, ища фасоль TaskExecutor для использования, для выполнения метода @Async. весна неожиданно подхватила бочонок clientInboundChannelExecutor, который присутствовал из-за @EnableWebSocketMessageBroker. Использование этого компонента вызвало создание WebSocketMessagingAutoConfiguration, в котором был создан компонент objectMapper (для json-serialization), который использует службы, которые используют DAO-репозитории, которые зависят от dataSource. Итак, все эти бобы были созданы.

Потому что DataSourceInitializerPostProcessor не был зарегистрирован в то время, DataSourceInitializer был создан много позже, после миграции пролетел.

документация Javadoc для @EnableAsync говорит следующее:

По умолчанию SimpleAsyncTaskExecutor будет использоваться для обработки метод асинхронного вызовов.Кроме того, аннотированные методы, имеющие тип возврата void, не могут передавать какое-либо исключение обратно вызывающему. По умолчанию такие неперехваченные исключения регистрируются только.

Я предположил, что SimpleAsyncTaskExecutor будет создан для запуска @Async методы, но вместо того, чтобы пружинный поднял существующий компонент с типом соответствия.

Так решение этой проблемы было реализоватьAsyncConfigurer и обеспечить мою собственную Executor. Это также предлагается в Javadoc из @EnableAsync:

Чтобы настроить все это, реализовать AsyncConfigurer и обеспечивают: * собственный Исполнителю с помощью метода getAsyncExecutor(), и * собственный AsyncUncaughtExceptionHandler через getAsyncUncaughtExceptionHandler (метод) ,

С помощью этой настройки настройка БД выполняется так, как ожидалось.