Comment puis-je arrêter par programme une application Spring Boot sans arrêter la machine virtuelle ?
Dans d'autres œuvres, quel est le contraire de
new SpringApplication(Main.class).run(args);
Comment puis-je arrêter par programme une application Spring Boot sans arrêter la machine virtuelle ?
Dans d'autres œuvres, quel est le contraire de
new SpringApplication(Main.class).run(args);
Réponses:
Fermer un SpringApplication
signifie essentiellement fermer le sous-jacent ApplicationContext
. La SpringApplication#run(String...)
méthode vous donne cela ApplicationContext
sous forme de fichier ConfigurableApplicationContext
. Vous pouvez ensuite le close()
faire vous-même.
Par exemple,
@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();
}
}
Vous pouvez également utiliser la static
SpringApplication.exit(ApplicationContext, ExitCodeGenerator...)
méthode d'assistance pour le faire pour vous. Par exemple,
@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
peut être utilisé. Vous pouvez simplement revenir de la main
méthode pour quitter gracieusement (code de sortie 0).
Dans une application de démarrage au printemps, vous pouvez utiliser quelque chose comme ça
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
peut être automatiquement injecté dans d'autres beans.
Cela fonctionne, même fait est imprimé.
SpringApplication.run(MyApplication.class, args).close();
System.out.println("done");
Donc en ajoutant .close()
aprèsrun()
Explication:
public ConfigurableApplicationContext run(String... args)
Exécutez l'application Spring, en créant et en actualisant un nouveau ApplicationContext. Paramètres:
args
- les arguments de l'application (généralement passés d'une méthode principale Java)Renvoie: un ApplicationContext en cours d'exécution
et:
void close()
Fermez ce contexte d'application, libérant toutes les ressources et verrous que l'implémentation peut contenir. Cela inclut la destruction de tous les beans singleton mis en cache. Remarque: n'invoque pas close sur un contexte parent; les contextes parents ont leur propre cycle de vie indépendant.Cette méthode peut être appelée plusieurs fois sans effets secondaires: les appels de fermeture suivants sur un contexte déjà fermé seront ignorés.
Donc, fondamentalement, cela ne fermera pas le contexte parent, c'est pourquoi la VM ne se ferme pas.
SpringApplication.exit(appContext, () -> returnCode)
.
SpringApplication.run(MyApplication.class, args)
, il n'y a pas de contexte parent. Il n'y a qu'un seul contexte, le contexte créé et renvoyé par run
, que vous ensuite immédiatement close
. @Michael a raison. Cela ne fonctionnera pas pour les programmes qui ont besoin de faire quoi que ce soit après l'initialisation du contexte Spring, qui est la plupart des programmes.
Dans l'application, vous pouvez utiliser SpringApplication
. Cela a une exit()
méthode statique qui prend deux arguments: le ApplicationContext
et un ExitCodeGenerator
:
c'est à dire que vous pouvez déclarer cette méthode:
@Autowired
public void shutDown(ExecutorServiceExitCodeGenerator exitCodeGenerator) {
SpringApplication.exit(applicationContext, exitCodeGenerator);
}
Dans les tests d'intégration, vous pouvez y parvenir en ajoutant une @DirtiesContext
annotation au niveau de la classe:
@DirtiesContext(classMode=ClassMode.AFTER_CLASS)
- Le ApplicationContext associé sera marqué comme sale après la classe de test.@DirtiesContext(classMode=ClassMode.AFTER_EACH_TEST_METHOD)
- Le ApplicationContext associé sera marqué comme sale après chaque méthode de test de la classe.c'est à dire
@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 {
...
Cela garantira que l'application SpringBoot est fermée correctement et que les ressources sont libérées vers le système d'exploitation,
@Autowired
private ApplicationContext context;
@GetMapping("/shutdown-app")
public void shutdownApp() {
int exitCode = SpringApplication.exit(context, (ExitCodeGenerator) () -> 0);
System.exit(exitCode);
}