2016-04-21 5 views
2

Ich wollte @Async Methoden (für das parallele Senden von Mails) in meiner SpringBoot-Anwendung einführen. Aber wenn ich die @EnableAsync Annotation auf unserer Hauptklasse (mit @SpringBootApplication annotiert) setzen, werden die Flyway DB-Migrationen ausgeführt, bevor die DataSourceInitializer (die schema.sql und data.sql für meine Tests ausführt) ausgeführt wird.Spring @EnableAsync bricht die Initialisierungsreihenfolge der Bean ab?

Die erste Operation mit einer 'zu migrierenden' Datenbanktabelle schlägt fehl.

Durch das Entfernen der @EnableAsync wird alles wieder normal. Warum passiert das und wie kann ich das beheben (oder das Problem umgehen)?

aktualisieren Einige weitere Erkenntnisse: @EnableAsync(mode = AdviceMode.ASPECTJ) hält die ursprüngliche Reihenfolge der DB-Setup, aber die @Async Verfahren läuft auf dem selben Thread wie Anrufer-Thread dann. Ich habe auch gesehen, dass der Bean 'objectPostProcessor' früher erstellt wird (3. Bean), wenn @EnableAsync nicht vorhanden ist oder @EnableAsync(mode = AdviceMode.ASPECTJ) verwendet wird. Wenn nur @EnableAsync verwendet wird, wird diese Bean viel später erstellt.

Update 2 Während ich nicht in der Lage war, ein minimal-Projekt zu erstellen, die noch das Problem reproduziert, fand ich heraus, dass die richtige DB-Setup, um in meiner betroffenen Anwendung gestellt wird, wenn ich die @EnableWebSocketMessageBroker in dem folgenden Kommentar aus:

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

Bean 'webSocketConfig' ist die erste bean erstellt (gemäß INFO-level Konsolausgabe), wenn @EnableWebSocketMessageBroker vorhanden ist.

+0

Erhalten Sie irgendwelche Fehler von Flyway? Wie stellen Sie sicher, dass das asynchrone Zeug immer noch ausgeführt wird, nachdem die Migration abgeschlossen wurde? – Thilo

+0

Bitte überprüfen Sie mein Update zu der Frage. Eigentlich scheint die Migration gut zu funktionieren, die gesamte DB wird später neu erstellt. – sorrymissjackson

+0

Ich verstehe die Frage nicht. Sie müssen den Migrationscode ausführen, bevor Sie versuchen, die Datenbank zu verwenden. Warum möchten Sie es "asynchron" ausführen? – Thilo

Antwort

1

Es stellte sich heraus, dass sowohl die @EnableAsync als auch die @EnableWebSocketMessageBroker in meiner Anwendung den beschriebenen Effekt verursachten.

Entfernen eines davon, das erwartete Verhalten wiederhergestellt, in diesem Fall die DataSourceInitializerPostProcessor erstellt die DataSourceInitializer, die Ausführung von schema.sql und data.sql ausgelöst, bevor Migrationen von Flugwegen stattfand.

Wenn beide Anmerkungen vorhanden waren, trat die Registrierung des BeanPostProcessor namens internalAsyncAnnotationProcessor auf, bevor das DataSourceInitializerPostProcessor registriert wurde. Die Ursache des Problems war, dass die Registrierung von internalAsyncAnnotationProcessor die Erzeugung der dataSource Bean als Nebeneffekt verursachte. Dieser Nebeneffekt wurde durch den Frühling verursacht, der nach einer TaskExecutor Bohne sucht, um die @Async Methodenausführung zu verwenden. Frühling unerwartet nahm die clientInboundChannelExecutor Bohne auf, die wegen der @EnableWebSocketMessageBroker anwesend war. Die Verwendung dieser Bean verursachte die Instanziierung von WebSocketMessagingAutoConfiguration, die die objectMapper-Bean (für Json-Serialisierung) erzeugte, die Dienste verwendet, die DAO-Repositories verwenden, die von dataSource abhängen. So wurden alle diese Bohnen erstellt.

Da DataSourceInitializerPostProcessor zu diesem Zeitpunkt noch nicht einmal registriert war, wurde DataSourceInitializer viel später erstellt, nachdem die Migration der Zugbahn stattgefunden hatte.

Die javadoc für @EnableAsync sagt die folgenden:

Standardmäßig wird ein SimpleAsyncTaskExecutor verwendet wird asynchrone Methodenaufrufe zu verarbeiten.Außerdem können annotierte Methoden mit einem void-Rückgabetyp keine Ausnahme zurück an den Aufrufer senden. Solche nicht abgefangenen Ausnahmen werden standardmäßig nur protokolliert.

I angenommen, dass ein SimpleAsyncTaskExecutor wird die @Async Methoden ausgeführt geschaffen werden, sondern Feder eine bestehende bean mit einer passenden Art aufgenommen.

So ist die Lösung für dieses Problem warAsyncConfigurer, zu implementieren und zu meinem eigenen Executor bieten. Dies spiegelt sich auch in der javadoc von @EnableAsync vorgeschlagen:

Um all dies zu gestalten, implementieren AsyncConfigurer und bietet: * Ihre eigene Executor durch den getAsyncExecutor() -Methode, und * Ihre eigenen AsyncUncaughtExceptionHandler durch die getAsyncUncaughtExceptionHandler() -Methode .

Mit dieser Optimierung wird das DB-Setup wieder wie erwartet ausgeführt.