Como posso desligar programaticamente um aplicativo Spring Boot sem encerrar a VM ?
Em outras obras, o que é o oposto de
new SpringApplication(Main.class).run(args);
Como posso desligar programaticamente um aplicativo Spring Boot sem encerrar a VM ?
Em outras obras, o que é o oposto de
new SpringApplication(Main.class).run(args);
Respostas:
Fechar um SpringApplication
significa basicamente fechar o subjacente ApplicationContext
. O SpringApplication#run(String...)
método fornece isso ApplicationContext
como um ConfigurableApplicationContext
. Você pode então fazer close()
isso sozinho.
Por exemplo,
@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();
}
}
Como alternativa, você pode usar o static
SpringApplication.exit(ApplicationContext, ExitCodeGenerator...)
método auxiliar para fazer isso por você. Por exemplo,
@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);
}
}
ExitCodeGenerator
pode ser usado. Você pode simplesmente retornar do main
método para sair normalmente (código de saída 0).
Em um aplicativo de inicialização de primavera, você pode usar algo assim
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);
}
}
ApplicationContext
pode ser injetado automaticamente em outros grãos.
Isso funciona, mesmo quando feito é impresso.
SpringApplication.run(MyApplication.class, args).close();
System.out.println("done");
Então, adicionando .close()
depoisrun()
Explicação:
public ConfigurableApplicationContext run(String... args)
Execute o aplicativo Spring, criando e atualizando um novo ApplicationContext. Parâmetros:
args
- os argumentos do aplicativo (geralmente passados de um método principal Java)Retorna: um ApplicationContext em execução
e:
void close()
Feche este contexto de aplicativo, liberando todos os recursos e bloqueios que a implementação possa conter. Isso inclui destruir todos os beans singleton armazenados em cache. Nota: Não invoca o fechamento em um contexto pai; contextos pais têm seu próprio ciclo de vida independente.Este método pode ser chamado várias vezes sem efeitos colaterais: As chamadas de fechamento subsequentes em um contexto já fechado serão ignoradas.
Então, basicamente, não fechará o contexto pai, é por isso que a VM não fecha.
SpringApplication.exit(appContext, () -> returnCode)
.
SpringApplication.run(MyApplication.class, args)
, não há contexto pai. Há apenas um contexto, o contexto criado e retornado run
, que você imediatamente close
. @Michael está certo. Isso não funcionará para programas que precisam fazer qualquer coisa depois que o contexto Spring é inicializado, que é a maioria dos programas.
No aplicativo você pode usar SpringApplication
. Isso tem um exit()
método estático que leva dois argumentos: oe ApplicationContext
um ExitCodeGenerator
:
ou seja, você pode declarar este método:
@Autowired
public void shutDown(ExecutorServiceExitCodeGenerator exitCodeGenerator) {
SpringApplication.exit(applicationContext, exitCodeGenerator);
}
Nos testes de integração, você pode alcançá-lo adicionando @DirtiesContext
anotações no nível da classe:
@DirtiesContext(classMode=ClassMode.AFTER_CLASS)
- O ApplicationContext associado será marcado como sujo após a aula de teste.@DirtiesContext(classMode=ClassMode.AFTER_EACH_TEST_METHOD)
- O ApplicationContext associado será marcado como sujo após cada método de teste na classe.ie
@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 {
...
Isso garantirá que o aplicativo SpringBoot seja fechado corretamente e os recursos sejam liberados de volta para o sistema operacional,
@Autowired
private ApplicationContext context;
@GetMapping("/shutdown-app")
public void shutdownApp() {
int exitCode = SpringApplication.exit(context, (ExitCodeGenerator) () -> 0);
System.exit(exitCode);
}