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.