2016-05-06 4 views
3

Ich arbeite an einer Spring-Boot-JMS-Anwendung, die ausschließlich mit Bean-Annotationen eingerichtet ist und Nachrichten von WebSpereMQ liest. Alles funktioniert, außer ich kann nicht herausfinden, wie man diese Anwendung sicher herunterfahren kann. Sobald meine JMSListener-Methode alle Nachrichten liest, bleibt sie nur im Leerlauf. Ich stelle eine erste Verbindung zur Warteschlange her und greife auf die Warteschlangentiefe zu. Im Idealfall, wenn die Warteschlangentiefe Null ist, muss sie hochgefahren und heruntergefahren werden. Meine aktuelle Problemumgehung (und ich es nicht mögen) ist dieser kleine Methode nenne ich (aus dem Inneren des Hörers, Huch), wenn Tiefe Null ist:Sicheres Beenden einer Spring JMS-Anwendung

public void shutDownApplication() { 
     logger.info("Initiating shutdown of application..."); 
     System.out.println("Terminating application..."); 
     Thread.currentThread().interrupt(); 
     System.exit(0); 
    } 

ich diese Lösung nicht mögen. Und auch nicht Spring, weil dies offensichtlich als ein Fehler mitten im Prozess unterbrochen wird und bevor die Anwendung abstürzt, löst mein JMSListener einen Rollback aus und setzt die einzige letzte verbleibende Nachricht zurück in die Warteschlange.

habe ich versucht, ein paar andere Lösungen nach in den folgenden Quellen suchen:

How can I Stop/start/Pause a @JmsListener (the clean way)

How to gracefully shut down a Spring JMS MessageListenerAdapter

http://forum.spring.io/forum/spring-projects/integration/jms/124980-graceful-shutdown-of-jms-message-listener

Das ist meine letzte Lösung war:

public class JMSShutdownService { 

    public void initiateShutdown() { 
     JmsListenerEndpointRegistry jmsListenerEndpointRegistry = new JmsListenerEndpointRegistry(); 
     Collection<MessageListenerContainer> col = jmsListenerEndpointRegistry 
       .getListenerContainers(); 
     for (MessageListenerContainer cont : col) { 
      cont.stop(Thread.currentThread()); 
     } 
     System.exit(0); 
    } 

} 

Damit wird die Anwendung beendet, die letzte Nachricht wird jedoch weiterhin in die Warteschlange gestellt. Es gibt viele Feinheiten von Spring, die ich immer noch versuche zu verstehen, also kommt alles darauf an. Ich glaube, das Hauptproblem ist, dass es innerhalb des Zuhörers ist, den ich für das Herunterfahren signalisiere. Von dem, was ich erfahre, sollte der Hörer nicht dafür verantwortlich sein. Aber ich bin mir nicht sicher, wie ich eine Methode zum Herunterfahren der Anwendung definieren kann, bevor der Listener gestartet wird, oder wie ich aus dem Listener aussteigen kann, wenn die Warteschlangentiefe Null ist.

Irgendwelche Ideen?

Antwort

2
JmsListenerEndpointRegistry jmsListenerEndpointRegistry = new JmsListenerEndpointRegistry(); 

Das ist nutzlos; Eine neue Registrierung enthält keine Container. Wenn Sie @JmsListener verwenden, müssen Sie die Registrierung aus dem Anwendungskontext abrufen.

System.exit(0); 

Das tötet nur die JVM.

Die Quintessenz ist, dass Sie den Container auf einem anderen Thread stoppen sollten - verwenden Sie einen Task Executor, um einen neuen Thread zu starten, um den Container zu stoppen; Der Container wartet darauf, dass der Thread den Listener verlässt, bevor er anhält.

Nach dem Stoppen des Containers müssen Sie warten, bis die JVM beendet ist.

Woher wissen Sie, dass Sie fertig sind? Nach dem Stoppen des Containers kann eine weitere Nachricht angezeigt werden. In diesem Fall werden Sie wahrscheinlich im Protokoll ein Geräusch sehen, dass eine Nachricht zurückgewiesen wurde, weil der Container angehalten wurde.

EDIT

in meinen Zuhörern ...

... 
if (timeToShutDown()) { 
    Executors.newSingleThreadExecutor.execute(new Runnable() { 

     public void run() { 
      stopTheContainer(); 
     } 
    } 
} 
// exit the listener so the container can actually stop. 
+0

'eine Aufgabe Testamentsvollstrecker verwenden, um einen neuen Thread starten Sie den container' zu stoppen: Wann genau ist diese neue Thread-Erzeugung geschehen?Bevor der Zuhörer losgeht oder tatsächlich im Zuhörer? Dann ist dieser Thread derjenige, der dem Container sagt "Hey, ich habe das Signal bekommen, dass wir fertig sind, mach den runter"? –

+0

Richtig - der Listener kann bestimmen, dass es Zeit ist, 'Executors.newSingleThreadExecutor.executure.execute (...)' zu stoppen und dann den 'Runnable' anzuhalten, der den Listener-Thread zum Beenden freigibt und der Container darauf wartet bevor es tatsächlich aufhört. –

+0

Letzte Frage, und ich entschuldige mich dafür, da ich denke, ich kenne die Antwort, aber ich möchte bestätigen. Wenn Sie "und dann im Runnable" sagen, bezieht sich Runnable auf den neu erstellten Thread, yeah? –