Chiudere a livello di programmazione l'applicazione Spring Boot


109

Come posso programmazione arresto una primavera di avvio applicazione senza terminare la VM ?

In altri lavori, qual è il contrario di

new SpringApplication(Main.class).run(args);

1
Buon punto! Chiamare close () su quello dovrebbe fare il lavoro.
Axel Fontaine


@ AnandVarkeyPhilips No, sicuramente non lo è. Questo riguarda un'API, l'altro riguarda un modo per gli operatori di farlo.
Axel Fontaine

Va bene .. Il collegamento alla domanda potrebbe aiutare gli altri. Vuoi che elimini il commento sopra?
Anand Varkey Philips

Risposte:


111

Chiudere un SpringApplicationsignifica sostanzialmente chiudere il sottostante ApplicationContext. Il SpringApplication#run(String...)metodo ti dà che ApplicationContextcome file ConfigurableApplicationContext. Puoi quindi close()farlo da solo.

Per esempio,

@SpringBootApplication
public class Example {
    public static void main(String[] args) {
        ConfigurableApplicationContext ctx = SpringApplication.run(Example.class, args);
        // ...determine it's time to shut down...
        ctx.close();
    }
}

In alternativa, puoi utilizzare il static SpringApplication.exit(ApplicationContext, ExitCodeGenerator...)metodo helper per farlo per te. Per esempio,

@SpringBootApplication
public class Example {
    public static void main(String[] args) {
        ConfigurableApplicationContext ctx = SpringApplication.run(Example.class, args);
        // ...determine it's time to stop...
        int exitCode = SpringApplication.exit(ctx, new ExitCodeGenerator() {
            @Override
            public int getExitCode() {
                // no errors
                return 0;
            }
        });

        // or shortened to
        // int exitCode = SpringApplication.exit(ctx, () -> 0);

        System.exit(exitCode);
    }
}

1
Se uso ctx.close (); non è necessario chiamare System.exit (n) alla fine, giusto? contesto close () dovrebbe avere System.exit () all'interno?
Nega

2
@Denys No, il contesto non esce dal processo java alla chiusura. L'uscita nel mio esempio dimostra solo come ExitCodeGeneratorpuò essere utilizzato. Potresti semplicemente tornare dal mainmetodo per uscire con grazia (codice di uscita 0).
Sotirios Delimanolis

78

In un'applicazione di avvio primaverile puoi usare qualcosa di simile

ShutdownManager.java

import org.springframework.context.ApplicationContext;
import org.springframework.boot.SpringApplication;

@Component
class ShutdownManager{

    @Autowired
    private ApplicationContext appContext;

    public void initiateShutdown(int returnCode){
        SpringApplication.exit(appContext, () -> returnCode);
    }
}

16
Voto positivo per aver dimostrato che ApplicationContextpuò essere iniettato automaticamente in altri fagioli.
Anthony Chuinard

1
@snovelli come invocare il metodo di arresto di avvio? initiateShutdown (x), x = 0?
StackOverFlow

Quando c'è un arresto condizionale, questo può essere eseguito. SpringApplication.run (..). Close () eseguirà il completamento del programma.
Abubacker Siddik

perché SpringApplication. (appContext, () -> returnCode); perché non è possibile appContext.close (). qual è la differenza ?
Rams

@StackOverFlow Devi iniettare il bean dove ti serve e poi passare il codice di ritorno come suggerito (x = 0) se si sta spegnendo correttamente. Ad esempio, potresti iniettare Shutdown Manager in un RestController e consentire l'arresto remoto, oppure potresti iniettarlo in un monitoraggio di healthcheck che spegnerebbe la JVM in caso di servizi a valle mancanti
snovelli

36

Funziona, anche se viene stampato.

  SpringApplication.run(MyApplication.class, args).close();
  System.out.println("done");

Quindi aggiungendo .close()doporun()

Spiegazione:

public ConfigurableApplicationContext run(String... args)

Esegui l'applicazione Spring, creando e aggiornando un nuovo ApplicationContext. parametri:

args - gli argomenti dell'applicazione (solitamente passati da un metodo principale Java)

Restituisce: un ApplicationContext in esecuzione

e:

void close()Chiudere questo contesto dell'applicazione, rilasciando tutte le risorse e i blocchi che l'implementazione potrebbe contenere. Ciò include la distruzione di tutti i bean singleton memorizzati nella cache. Nota: non richiama close su un contesto genitore; i contesti genitore hanno il loro ciclo di vita indipendente.

Questo metodo può essere chiamato più volte senza effetti collaterali: le successive chiamate di chiusura su un contesto già chiuso verranno ignorate.

Quindi, in pratica, non chiuderà il contesto genitore, ecco perché la VM non si chiude.


2
Solo un promemoria che questa soluzione funziona per processi di breve durata come batch, ma non utilizzarla sulle applicazioni Spring MVC. L'applicazione si arresta solo dopo l'avvio.
Michael COLL

@MichaelCOLL la domanda riguarda come arrestare programmaticamente un'app di avvio primaverile indipendentemente dal tipo. Funziona anche per Spring MVC
ACV

1
@ACV Hai ragione funziona, funziona molto bene. Ma per un'app che deve rimanere attiva (come l'app Spring MVC), penso che non sia il modo migliore per farlo. Nel mio caso, ho usato SpringApplication.exit(appContext, () -> returnCode).
Michael COLL

1
A quale VM ti riferisci nella tua ultima riga? Se stai avviando la tua applicazione Spring Boot con SpringApplication.run(MyApplication.class, args), non esiste un contesto genitore. C'è solo un contesto, il contesto creato e restituito da run, che poi immediatamente close. @Michael ha ragione. Questo non funzionerà per i programmi che devono fare qualcosa dopo che il contesto Spring è stato inizializzato, che è la maggior parte dei programmi.
Salvatore

@ Salvatore JVM. C'è un contesto genitore. Qui stiamo parlando di come chiudere un'applicazione Spring Boot. Normalmente non chiudi le applicazioni web in questo modo. Quindi questo meccanismo viene solitamente utilizzato per applicazioni di breve durata che fanno qualcosa e poi devono essere interrotte. Per impostazione predefinita, Spring boot continuerà a funzionare anche dopo aver terminato l'elaborazione in batch, quindi è lì che si desidera utilizzare questo meccanismo.
ACV

3

Nell'applicazione puoi usare SpringApplication. Questo ha un exit()metodo statico che accetta due argomenti: il ApplicationContexte un ExitCodeGenerator:

cioè puoi dichiarare questo metodo:

@Autowired
public void shutDown(ExecutorServiceExitCodeGenerator exitCodeGenerator) {
    SpringApplication.exit(applicationContext, exitCodeGenerator);
}

All'interno dei test di integrazione puoi ottenerlo aggiungendo @DirtiesContextannotazioni a livello di classe:

  • @DirtiesContext(classMode=ClassMode.AFTER_CLASS) - L'ApplicationContext associato verrà contrassegnato come sporco dopo la classe di test.
  • @DirtiesContext(classMode=ClassMode.AFTER_EACH_TEST_METHOD) - L'ApplicationContext associato verrà contrassegnato come sporco dopo ogni metodo di test nella classe.

vale a dire

@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(classes = {Application.class},
    webEnvironment= SpringBootTest.WebEnvironment.DEFINED_PORT, properties = {"server.port:0"})
@DirtiesContext(classMode= DirtiesContext.ClassMode.AFTER_CLASS)
public class ApplicationIT {
...

Ok. Dove dovrei ottenere ExecutorServiceExitCodeGenerator? Se è un bean, puoi mostrare il codice dello snippet di creazione (e da quale classe è stato creato)? In quale classe va messo il metodo shutDown (ExecutorServiceExitCodeGenerator exitCodeGenerator)?
Vlad G.

2

Ciò assicurerà che l'applicazione SpringBoot sia chiusa correttamente e che le risorse vengano rilasciate di nuovo al sistema operativo,

@Autowired
private ApplicationContext context;

@GetMapping("/shutdown-app")
public void shutdownApp() {

    int exitCode = SpringApplication.exit(context, (ExitCodeGenerator) () -> 0);
    System.exit(exitCode);
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.