¿Cómo puedo apagar programáticamente una aplicación Spring Boot sin terminar la VM ?
En otras obras, ¿qué es lo contrario de
new SpringApplication(Main.class).run(args);
¿Cómo puedo apagar programáticamente una aplicación Spring Boot sin terminar la VM ?
En otras obras, ¿qué es lo contrario de
new SpringApplication(Main.class).run(args);
Respuestas:
Cerrar un SpringApplication
básicamente significa cerrar el subyacente ApplicationContext
. El SpringApplication#run(String...)
método te da eso ApplicationContext
como un ConfigurableApplicationContext
. Entonces puedes close()
hacerlo tú mismo.
Por ejemplo,
@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();
}
}
Alternativamente, puede utilizar el static
SpringApplication.exit(ApplicationContext, ExitCodeGenerator...)
método de ayuda para hacerlo por usted. Por ejemplo,
@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
se puede usar. Puede volver del main
método para salir con gracia (código de salida 0).
En una aplicación de arranque de primavera, puede usar algo como esto
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
se puede inyectar automáticamente en otros granos.
Esto funciona, incluso hecho está impreso.
SpringApplication.run(MyApplication.class, args).close();
System.out.println("done");
Entonces agregando .close()
despuésrun()
Explicación:
public ConfigurableApplicationContext run(String... args)
Ejecute la aplicación Spring, creando y actualizando un nuevo ApplicationContext. Parámetros:
args
- los argumentos de la aplicación (generalmente pasados desde un método principal de Java)Devuelve: un ApplicationContext en ejecución
y:
void close()
Cierre este contexto de aplicación, liberando todos los recursos y bloqueos que pueda contener la implementación. Esto incluye destruir todos los beans singleton almacenados en caché. Nota: No invoca cerrar en un contexto principal; Los contextos principales tienen su propio ciclo de vida independiente.Este método se puede llamar varias veces sin efectos secundarios: se ignorarán las llamadas de cierre posteriores en un contexto ya cerrado.
Entonces, básicamente, no cerrará el contexto principal, por eso la VM no se cierra.
SpringApplication.exit(appContext, () -> returnCode)
.
SpringApplication.run(MyApplication.class, args)
, entonces no hay un contexto principal. Solo hay un contexto, el contexto creado y devuelto por run
, que luego inmediatamente close
. @Michael tiene razón. Esto no funcionará para los programas que necesitan hacer algo después de que se inicialice el contexto Spring, que es la mayoría de los programas.
En la aplicación puedes usar SpringApplication
. Tiene un exit()
método estático que toma dos argumentos: el ApplicationContext
y un ExitCodeGenerator
:
es decir, puede declarar este método:
@Autowired
public void shutDown(ExecutorServiceExitCodeGenerator exitCodeGenerator) {
SpringApplication.exit(applicationContext, exitCodeGenerator);
}
Dentro de las pruebas de Integración puede lograrlo agregando una @DirtiesContext
anotación a nivel de clase:
@DirtiesContext(classMode=ClassMode.AFTER_CLASS)
- El ApplicationContext asociado se marcará como sucio después de la clase de prueba.@DirtiesContext(classMode=ClassMode.AFTER_EACH_TEST_METHOD)
- El ApplicationContext asociado se marcará como sucio después de cada método de prueba en la clase.es decir
@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 {
...
Esto asegurará que la aplicación SpringBoot se cierre correctamente y que los recursos se devuelvan al sistema operativo,
@Autowired
private ApplicationContext context;
@GetMapping("/shutdown-app")
public void shutdownApp() {
int exitCode = SpringApplication.exit(context, (ExitCodeGenerator) () -> 0);
System.exit(exitCode);
}