2014-10-12 15 views
14

Ich erstelle eine Befehlszeilen-Java-Anwendung mithilfe von Spring Boot, damit es schnell funktioniert.So beenden Sie eine Spring Boot-Befehlszeilenanwendung

Die Anwendung lädt verschiedene Dateitypen (z. B. CSV) und lädt sie in eine Cassandra-Datenbank. Es verwendet KEINE Web-Komponenten, es ist keine Web-Anwendung.

Das Problem, das ich habe, ist die Anwendung zu stoppen, wenn die Arbeit erledigt ist. Ich verwende die Spring CommandLineRunner-Schnittstelle mit einer @Component, um die Aufgaben auszuführen, wie unten gezeigt, aber wenn die Arbeit abgeschlossen ist, hört die Anwendung nicht auf, sie läuft aus irgendeinem Grund weiter und ich finde keine Möglichkeit, sie zu stoppen.

@Component 
public class OneTimeRunner implements CommandLineRunner { 

    @Autowired 
    private CassandraOperations cassandra; 

    @Autowired 
    private ConfigurableApplicationContext context; 

    @Override 
    public void run(String... args) throws Exception { 
     // do some work here and then quit 
     context.close(); 
    } 
} 

UPDATE: Das Problem scheint spring-cassandra, zu sein, da es nichts anderes im Projekt ist. Wer weiß, warum im Hintergrund Threads laufen, die verhindern, dass die Anwendung beendet wird?

UPDATE: Das Problem verschwand durch die Aktualisierung auf die neueste Springboot-Version.

+0

Irgendeine Lösung zu diesem? Es passiert mit normalen Spring Boot (ohne Cassandra) – ACV

+1

@ACV Nein, ich lebe nur damit. Ich habe gelernt, dass einige Federmodule eigene Fäden spawnen, z. Cassandra hat einen Thread-Pool für Verbindungen oder RabbitMQ, wenn Sie Listener-Container verwenden. Nach dem Aufruf von 'context.close()' dauert das Herunterfahren einige Zeit, um die Anwendung zu beenden. – ESala

+0

Siehe meine Antwort unter – ACV

Antwort

8

Die Antwort hängt davon ab, was es noch macht Arbeit. Das können Sie wahrscheinlich mit einem Thread-Dump herausfinden (zB mit jstack). Aber wenn es etwas ist, das von Spring gestartet wurde, sollten Sie ConfigurableApplicationContext.close() verwenden können, um die App in Ihrer main() - Methode (oder in der CommandLineRunner) zu stoppen.

+0

Ok, ich debuggte die Anwendung mit einem Breakpoint und es gibt 17: Thread [New I/O Worker # (1-17)].Ich muss darüber nachforschen. Über die ConfigurableApplicationContext.close() dauert es etwa 30 Sekunden, um die Anwendung zu stoppen, ist das normal? – ESala

+0

Es wird auf alles warten müssen, um die Threads freizugeben. Klingt wie eine Auszeit für mich. –

+0

Genau, ich vermute, die Spring Cassandra hält diese Threads aus irgendeinem Grund am Laufen. – ESala

9

Ich fand eine Lösung. Sie können dies verwenden:

public static void main(String[] args) { 
    SpringApplication.run(RsscollectorApplication.class, args).close(); 
    System.out.println("done"); 
} 

Verwenden Sie einfach .close on run.

+0

naja ja .... wenn du dir den Code auf die Frage anschaust, mache ich genau das. 'SpringApplication.run (Main.class, args)' gibt einen 'ConfigurableApplicationContext' zurück, den Sie später speichern oder' @ Autowire' verwenden können. Das Problem, das ich in dieser Frage habe, ist, dass nach dem Aufruf von 'close()' im Kontext die Anwendung für einige Zeit anhält. – ESala

+0

OK, klar. Es könnte sein, dass die Dateien einige Zeit benötigen, um in die Datenbank zu gelangen – ACV

4

Ich traf dieses Problem auch in meinem aktuellen Projekt (Spring-Boot-Anwendung). Meine Lösung ist:

// releasing all resources 
((ConfigurableApplicationContext) ctx).close(); 
// Close application 
System.exit(0); 

context.close() nicht unsere Konsolenanwendung stoppen, es ist nur die Ressourcen freigeben.

0

Verwenden Sie org.springframework.boot.SpringApplication#exit. Z.B.

@Component 
public class OneTimeRunner implements CommandLineRunner { 

    @Autowired 
    private ConfigurableApplicationContext context; 

    @Override 
    public void run(String... args) throws Exception { 
     SpringApplication.exit(context); 
    } 
} 
1

Dies ist eine Kombination aus @EliuX Antwort mit @Quan Vo ein. Danke euch beiden!

Der Hauptunterschied ist, dass ich den SpringApplication.exit (Kontext) Response-Code als Parameter an die System.exit() übergeben, wenn Sie also einen Fehler beim Schließen des Spring-Kontextes bemerken.

Die SpringApplication.exit() schließt den Spring-Kontext.

Die System.exit() wird die Anwendung schließen.

@Component 
public class OneTimeRunner implements CommandLineRunner { 

    @Autowired 
    private ConfigurableApplicationContext context; 

    @Override 
    public void run(String... args) throws Exception { 
     System.exit(SpringApplication.exit(context)); 
    } 
}