Encerrar um aplicativo de inicialização Spring

Encerrar um aplicativo de inicialização Spring

1. Visão geral

Gerenciar o ciclo de vida do Spring Boot Application é muito importante para um sistema pronto para produção. O container Spring lida com a criação, inicialização e destruição de todos os Beans com a ajuda doApplicationContext.

A ênfase deste artigo é a fase de destruição do ciclo de vida. Mais especificamente, veremos diferentes maneiras de desligar um aplicativo Spring Boot.

Para saber mais sobre como configurar um projeto usando Spring Boot, verifique o artigoSpring Boot Starter ou leiaSpring Boot Configuration.

2. Ponto final de desligamento

Por padrão, todos os endpoints são habilitados no Spring Boot Application, exceto/shutdown; isso é, naturalmente, parte dos pontos finais deActuator.

Esta é a dependência do Maven para configurá-los:


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

E, se quisermos também configurar o suporte de segurança, precisamos:


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

Por último, habilitamos o endpoint de desligamento no arquivoapplication.properties:

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

Observe que também precisamos expor os pontos de extremidade do atuador que queremos usar. No exemplo acima, expusemos todos os pontos finais do atuador que incluirão o ponto final/shutdown.

To shut down the Spring Boot application, we simply call a POST method like this:

curl -X POST localhost:port/actuator/shutdown

Nesta chamada, oport representa a porta do atuador.

3. Fechar contexto do aplicativo

Também podemos chamar o métodoclose() diretamente usando o contexto do aplicativo.

Vamos começar com um exemplo de criação de um contexto e fechá-lo:

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

This destroys all the beans, releases the locks, then closes the bean factory. Para verificar o desligamento do aplicativo, usamos o retorno de chamada do ciclo de vida padrão do Spring com a anotação@PreDestroy:

public class TerminateBean {

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

Também temos que adicionar um bean deste tipo:

@Configuration
public class ShutdownConfig {

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

Aqui está o resultado após a execução deste exemplo:

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

O que é importante ter em mente aqui:while closing the application context, the parent context isn’t affected due to separate lifecycles.

3.1. Feche o contexto atual do aplicativo

No exemplo acima, criamos um contexto de aplicativo filho e usamos o métodoclose() para destruí-lo.

Se quisermos fechar o contexto atual, uma solução é simplesmente chamar o endpoint/shutdown do atuador.

No entanto, também podemos criar nosso próprio terminal personalizado:

@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;

    }
}

Aqui, adicionamos um controlador que implementa a interfaceApplicationContextAware e substitui o método setter para obter o contexto do aplicativo atual. Então, em um método de mapeamento, estamos simplesmente chamando o métodoclose().

Podemos então chamar nosso novo terminal para desligar o contexto atual:

curl -X POST localhost:port/shutdownContext

Claro, se você adicionar um endpoint como este em um aplicativo da vida real, você também desejará protegê-lo.

4. SairSpringApplication

SpringApplication registra um ganchoshutdown com a JVM para garantir que o aplicativo seja encerrado de forma adequada.

Beans podem implementar a interfaceExitCodeGenerator para retornar um código de erro específico:

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);

O mesmo código com o aplicativo do Java 8 lambdas:

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

After calling the System.exit(exitCode), the program terminates with a 0 return code:

Process finished with exit code 0

5. Mate o processo do aplicativo

Por fim, também podemos desligar um aplicativo de inicialização Spring de fora do aplicativo usando um script bash. Nossa primeira etapa para esta opção é fazer com que o contexto do aplicativo grave seu PID em um arquivo:

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

A seguir, crie um arquivoshutdown.bat com o seguinte conteúdo:

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

A execução deshutdown.bat extrai a ID do processo do arquivoshutdown.pide usa o comandokill para encerrar o aplicativo de inicialização.

6. Conclusão

Neste artigo rápido, cobrimos alguns métodos simples que podem ser usados ​​para desligar um aplicativo Spring Boot em execução.

Embora seja responsabilidade do desenvolvedor escolher um método apropriado; todos esses métodos devem ser usados ​​por design e propositalmente.

Por exemplo,.exit() é preferível quando precisamos passar um código de erro para outro ambiente, digamos JVM para outras ações. UsandoApplication PID gives more flexibility, as we can also start or restart the application com o uso do script bash.

Finalmente,/shutdown está aqui para tornar possívelterminate the applications externally via HTTP. Para todos os outros casos,.close() funcionará perfeitamente.

Como de costume, o código completo para este artigo está disponível emGitHub project.