Arrestare un'applicazione Spring Boot

1. Panoramica

La gestione del ciclo di vita dell'applicazione Spring Boot è molto importante per un sistema pronto per la produzione. Il contenitore Spring gestisce la creazione, l'inizializzazione e la distruzione di tutti i bean con l'aiuto di ApplicationContext.

L'enfasi di questo articolo è la fase di distruzione del ciclo di vita. Più specificamente, daremo uno sguardo a diversi modi per chiudere un'applicazione Spring Boot.

Per ulteriori informazioni su come impostare un progetto utilizzando Spring Boot, consulta l'articolo Spring Boot Starter o consulta la configurazione Spring Boot.

2. Endpoint di arresto

Per impostazione predefinita, tutti gli endpoint sono abilitati nell'applicazione Spring Boot tranne / shutdown ; questo è, naturalmente, parte degli endpoint di Actuator .

Ecco la dipendenza da Maven per configurarli:

 org.springframework.boot spring-boot-starter-actuator 

E, se vogliamo impostare anche il supporto per la sicurezza, abbiamo bisogno di:

 org.springframework.boot spring-boot-starter-security 

Infine, abilitiamo l'endpoint di arresto nel file application.properties :

management.endpoints.web.exposure.include=* management.endpoint.shutdown.enabled=true endpoints.shutdown.enabled=true

Si noti che dobbiamo anche esporre tutti gli endpoint dell'attuatore che vogliamo utilizzare. Nell'esempio sopra, abbiamo esposto tutti gli endpoint dell'attuatore che includeranno l' endpoint / shutdown .

Per chiudere l'applicazione Spring Boot, chiamiamo semplicemente un metodo POST come questo :

curl -X POST localhost:port/actuator/shutdown

In questa chiamata, la porta rappresenta la porta dell'attuatore.

3. Chiudere il contesto dell'applicazione

Possiamo anche chiamare il metodo close () direttamente utilizzando il contesto dell'applicazione.

Cominciamo con un esempio di creazione di un contesto e chiusura:

ConfigurableApplicationContext ctx = new SpringApplicationBuilder(Application.class).web(WebApplicationType.NONE).run(); System.out.println("Spring Boot application started"); ctx.getBean(TerminateBean.class); ctx.close();

Questo distrugge tutti i fagioli, rilascia i blocchi, quindi chiude la fabbrica di fagioli . Per verificare l'arresto dell'applicazione, utilizziamo il callback del ciclo di vita standard di Spring con l' annotazione @PreDestroy :

public class TerminateBean { @PreDestroy public void onDestroy() throws Exception { System.out.println("Spring Container is destroyed!"); } }

Dobbiamo anche aggiungere un fagiolo di questo tipo:

@Configuration public class ShutdownConfig { @Bean public TerminateBean getTerminateBean() { return new TerminateBean(); } }

Ecco l'output dopo aver eseguito questo esempio:

Spring Boot application started Closing [email protected] DefaultLifecycleProcessor - Stopping beans in phase 0 Unregistering JMX-exposed beans on shutdown Spring Container is destroyed!

La cosa importante qui da tenere a mente: mentre si chiude il contesto dell'applicazione, il contesto padre non viene influenzato a causa di cicli di vita separati .

3.1. Chiudi il contesto dell'applicazione corrente

Nell'esempio sopra, abbiamo creato un contesto dell'applicazione figlio, quindi abbiamo utilizzato il metodo close () per distruggerlo.

Se vogliamo chiudere il contesto corrente, una soluzione è chiamare semplicemente l' endpoint dell'attuatore / arresto .

Tuttavia, possiamo anche creare il nostro endpoint personalizzato:

@RestController public class ShutdownController implements ApplicationContextAware { private ApplicationContext context; @PostMapping("/shutdownContext") public void shutdownContext() { ((ConfigurableApplicationContext) context).close(); } @Override public void setApplicationContext(ApplicationContext ctx) throws BeansException { this.context = ctx; } }

Qui abbiamo aggiunto un controller che implementa l' interfaccia ApplicationContextAware e sostituisce il metodo setter per ottenere il contesto dell'applicazione corrente. Quindi, in un metodo di mappatura, stiamo semplicemente chiamando il metodo close () .

Possiamo quindi chiamare il nostro nuovo endpoint per chiudere il contesto corrente:

curl -X POST localhost:port/shutdownContext

Ovviamente, se aggiungi un endpoint come questo in un'applicazione reale, vorrai proteggerlo anche tu.

4. Esci da SpringApplication

SpringApplication registra un hook di arresto con la JVM per assicurarsi che l'applicazione venga chiusa in modo appropriato.

I bean possono implementare l' interfaccia ExitCodeGenerator per restituire un codice di errore specifico:

ConfigurableApplicationContext ctx = new SpringApplicationBuilder(Application.class) .web(WebApplicationType.NONE).run(); int exitCode = SpringApplication.exit(ctx, new ExitCodeGenerator() { @Override public int getExitCode() { // return the error code return 0; } }); System.exit(exitCode);

Lo stesso codice con l'applicazione di Java 8 lambda:

SpringApplication.exit(ctx, () -> 0);

Dopo aver chiamato System.exit (exitCode) , il programma termina con un codice di ritorno 0 :

Process finished with exit code 0

5. Termina il processo dell'app

Infine, possiamo anche chiudere un'applicazione Spring Boot dall'esterno dell'applicazione utilizzando uno script bash. Il nostro primo passo per questa opzione è fare in modo che il contesto dell'applicazione scriva il suo PID in un file:

SpringApplicationBuilder app = new SpringApplicationBuilder(Application.class) .web(WebApplicationType.NONE); app.build().addListeners(new ApplicationPidFileWriter("./bin/shutdown.pid")); app.run();

Successivamente, crea un file shutdown.bat con il seguente contenuto:

kill $(cat ./bin/shutdown.pid)

L'esecuzione di shutdown.bat estrae l'ID processo dal file shutdown.pid e utilizza il comando kill per terminare l'applicazione di avvio.

6. Conclusione

In questo breve articolo, abbiamo coperto alcuni semplici metodi che possono essere utilizzati per chiudere un'applicazione Spring Boot in esecuzione.

Mentre spetta allo sviluppatore scegliere un metodo appropriato; tutti questi metodi dovrebbero essere usati in base alla progettazione e di proposito.

Ad esempio, .exit () è preferito quando è necessario passare un codice di errore a un altro ambiente, ad esempio JVM per ulteriori azioni. L'uso del PID dell'applicazione offre maggiore flessibilità, poiché possiamo anche avviare o riavviare l'applicazione con l'uso dello script bash.

Infine, / shutdown è qui per rendere possibile terminare le applicazioni esternamente tramite HTTP . Per tutti gli altri casi .close () funzionerà perfettamente.

Come al solito, il codice completo per questo articolo è disponibile nel progetto GitHub.