2016-07-03 31 views
1

Ich habe eine Feder-Framework-basierte Anwendung mit AnnotationConfigApplicationContext erstellt.Warum können @PostConstruct und @Retryable nicht zusammen verwendet werden?

Eine Bean hat eine init-Methode, die eine Verbindung zu einem externen Dienst herstellt. Dies kann mit annotiert werden, um automatisch zu starten, sobald die Bean gestartet ist, was funktioniert.

Um irgendwelche Ausnahmen beim Erstellen dieser Verbindung zu behandeln, möchte ich, dass meine Init-Methode bis zu 5 mal wiederholt, wenn eine Ausnahme abgefangen wird. Wenn ich die Methode mit und @Retryable kommentieren sehe ich die Ausnahme wird einmal geworfen und das Programm beendet - Es scheint @Retryable hat keine Wirkung.

Ich habe @EnableRetry in der Konfigurationsklasse korrekt zusammen mit @Configuration verwendet. Ich habe eine andere Methode B auf der gleichen Bohne erstellt, die als retryable annotiert ist. Wenn diese Methode aufgerufen wird, nachdem die Bean instanziiert wurde, kann ich sehen, dass die Methode wie erwartet wiederholt wird, wenn eine Ausnahme ausgelöst wird.

Meine Gedanken, warum dies nicht funktioniert, ist möglicherweise etwas aspektbezogen oder das Postconstruct passiert bevor das spring-retry Element angehängt wird?

Gibt es tatsächlich eine bessere Möglichkeit, eine Initialisierungsmethode zu verwenden, die Ausnahmen behandeln kann und über Annotationen erneut versucht werden kann - anstatt programmgesteuert in der Methode zu versuchen?

Edit: Ich stimme jetzt zu, dass die Erstellung von Verbindungen zu externen Diensten nicht über @Postconstruct erfolgen soll. Dies kann verhindern, dass der gesamte Kontext initialisiert wird, wenn die Versuche fehlschlagen, was nachteilige Auswirkungen haben kann.

Dies beantwortet jedoch noch nicht die Frage, welcher Teil des Spring Frameworks diese beiden Annotationen nicht in Verbindung bringt.

Antwort

-1

"@Retryable" ist ein Aspekt, der von "spring-retry" angewendet wird. Dies wird nur angefügt, nachdem der Spring-Kontext vollständig erstellt wurde, dh nachdem alle '@PostConstruct' annotierten Methoden ausgeführt wurden, hat '@Retryable' keine Auswirkung.

+0

dieser Beitrag erklären besser https://stackoverflow.com/a/41856170/3309466 –

1

Ich würde vorschlagen, dass Sie tatsächlich eine ApplicationListener anwenden, die auf eine ContextRefreshedEvent hört und diese Methode mit Ihrer Wiederholungslogik annotiert hat. Diese Listener werden ausgelöst, sobald der Kontext vollständig aktualisiert und alle Beans ordnungsgemäß konfiguriert und verkabelt wurden.

+0

Ersetzen von PostConstruct mit EventListener ({ContextRefreshedEvent.Klasse}) in Kombination mit Retryable gibt das gewünschte Verhalten. Ich glaube, dass der Kontext im Anwendungslebenszyklus mehr als einmal aufgefrischt werden kann, so dass er möglicherweise nicht die Lösung ist, nach der ich suche. Die Methode zum Erstellen der Verbindung sollte nur einmal mit X-Wiederholungen ausgeführt werden. – UserF40

+0

Ja, ein Kontext kann mehrmals aktualisiert werden, aber bei jeder Aktualisierung werden Beans im Kontext von Frühling neu erstellt, sodass Sie das Verhalten erhalten, das Sie möchten. – Naros

2

Um irgendwelche Ausnahmen beim Erstellen dieser Verbindung zu behandeln, möchte ich, dass meine Init-Methode bis zu 5 mal wiederholt, wenn eine Ausnahme abgefangen wird.

Sie sollten NIEMALS mit Ressourcen in Init-Methoden verbinden; Sie sollten darauf warten, dass der Kontext zuerst erstellt wird.

Es ist viel besser zu implementieren SmartLifecycle und verbinden in start(). Auf diese Weise können Sie sicher sein, dass der gesamte Kontext initialisiert wurde, bevor Sie mit der Verbindung zu externen Ressourcen beginnen.

Auf diese Weise sollte die start() Methode von der Wiederholung Interzeptor beraten werden.

Wie @Naros vorgeschlagen hat, ist die ContextRefreshedEvent eine andere Alternative, aber Sie sollten niemals solche Sachen in nie tun.