Reiniciando programaticamente um aplicativo de inicialização Spring

Reiniciando programaticamente um aplicativo de inicialização Spring

1. Visão geral

Neste tutorial, mostraremos comoprogrammatically restart a Spring Boot application.

Reiniciar nosso aplicativo pode ser muito útil em alguns casos:

  • Recarregando arquivos de configuração ao alterar algum parâmetro

  • Alterando o perfil atualmente ativo no tempo de execução

  • Reinicializando o contexto do aplicativo por qualquer motivo

Embora este artigo cubra a funcionalidade de reiniciar um aplicativo Spring Boot, observe que também temos um ótimo tutorial sobreshutting down Spring Boot applications.

Agora, vamos explorar diferentes maneiras de implementar a reinicialização de um aplicativo Spring Boot.

2. Reinicie criando um novo contexto

Podemos reiniciar nosso aplicativo fechando o contexto do aplicativo e criando um novo contexto a partir do zero. Embora essa abordagem seja bastante simples, há alguns detalhes delicados com os quais devemos ter cuidado para fazê-la funcionar.

Vamos ver como implementar isso no métodomain de nosso aplicativo Spring Boot:

@SpringBootApplication
public class Application {

    private static ConfigurableApplicationContext context;

    public static void main(String[] args) {
        context = SpringApplication.run(Application.class, args);
    }

    public static void restart() {
        ApplicationArguments args = context.getBean(ApplicationArguments.class);

        Thread thread = new Thread(() -> {
            context.close();
            context = SpringApplication.run(Application.class, args.getSourceArgs());
        });

        thread.setDaemon(false);
        thread.start();
    }
}

Como podemos ver no exemplo acima, é importante recriar o contexto em um encadeamento não-daemon separado - dessa forma evitamos que o desligamento da JVM, acionado pelo métodoclose, feche nosso aplicativo. Caso contrário, nosso aplicativo pararia, pois a JVM não espera que os encadeamentos do daemon terminem antes de encerrá-los.

Além disso, vamos adicionar um endpoint REST por meio do qual podemos acionar a reinicialização:

@RestController
public class RestartController {

    @PostMapping("/restart")
    public void restart() {
        Application.restart();
    }
}

Aqui, adicionamos um controlador com um método de mapeamento que invoca nosso métodorestart.

Podemos então chamar nosso novo terminal para reiniciar o aplicativo:

curl -X POST localhost:port/restart

Claro, se adicionarmos um endpoint como este em um aplicativo da vida real, teremos que protegê-lo também.

3. Ponto final de reinicialização do atuador

Outra maneira de reiniciar nosso aplicativo é usar oRestartEndpoint integrado deSpring Boot Actuator.

Primeiro, vamos adicionar as dependências Maven necessárias:


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


    org.springframework.boot
    spring-cloud-starter

Em seguida, temos que habilitar o endpoint de reinicialização integrado em nosso arquivoapplication.properties:

management.endpoint.restart.enabled=true

Agora que configuramos tudo, podemos injetar oRestartEndpoint into nosso serviço:

@Service
public class RestartService {

    @Autowired
    private RestartEndpoint restartEndpoint;

    public void restartApp() {
        restartEndpoint.restart();
    }
}

No código acima, estamos usando oRestartEndpoint bean para reiniciar nosso aplicativo. Essa é uma boa maneira de reiniciar, porque precisamos apenas chamar um método que faça todo o trabalho.

Como podemos ver, usarRestartEndpoint é uma maneira simples de reiniciar nosso aplicativo. Por outro lado, há uma desvantagem com essa abordagem, pois ela exige a adição das bibliotecas mencionadas. Se ainda não os estivermos usando, isso pode ser uma sobrecarga apenas para esta funcionalidade. Nesse caso, podemos seguir a abordagem manual da seção anterior, pois ela requer apenas mais algumas linhas de código.

4. Atualizando o contexto do aplicativo

Em alguns casos, podemos recarregar o contexto do aplicativo chamando seu métodorefresh.

Embora esse método possa parecer promissor, apenas alguns tipos de contexto de aplicativo suportam a atualização de um contexto já inicializado. Por exemplo,FileSystemXmlApplicationContext,GroovyWebApplicationContext,e alguns outros o suportam.

Infelizmente, se tentarmos isso em um aplicativo Web Spring Boot, obteremos o seguinte erro:

java.lang.IllegalStateException: GenericApplicationContext does not support multiple refresh attempts:
just call 'refresh' once

Finalmente, embora existam alguns tipos de contexto que suportam várias atualizações, devemos evitar fazer isso. O motivo é que o métodorefresh foi projetado como um método interno usado pela estrutura para inicializar o contexto do aplicativo.

5. Conclusão

Neste artigo, exploramos várias maneiras diferentes de como reiniciar um aplicativo Spring Boot programaticamente.

Como sempre, podemos encontrar o código-fonte dos exemplos emGitHub.