Spring Boot uygulamasını programlı olarak kapatın


110

Bir Spring Boot uygulamasını VM'yi sonlandırmadan programlı olarak nasıl kapatabilirim ?

Diğer çalışmalarda, tam tersi ne

new SpringApplication(Main.class).run(args);

1
İyi bir nokta! İşi yapması gereken close () çağrısı.
Axel Fontaine


@AnandVarkeyPhilips Hayır, kesinlikle değil. Bu bir API ile ilgili, diğeri ise operasyonların bunu yapmasının bir yolu.
Axel Fontaine

Tamam .. Bu soru bağlantısı başkalarına yardımcı olabilir. Yukarıdaki yorumu silmemi ister misiniz?
Anand Varkey Philips

Yanıtlar:


111

Birini kapatmak, SpringApplicationtemelde temelini kapatmak anlamına gelir ApplicationContext. SpringApplication#run(String...)Yöntem size bunu sağlıyor ApplicationContextbir şekilde ConfigurableApplicationContext. O close()zaman kendiniz yapabilirsiniz .

Örneğin,

@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();
    }
}

Alternatif olarak, bunu sizin yerinize static SpringApplication.exit(ApplicationContext, ExitCodeGenerator...)yapmak için yardımcı yöntemi kullanabilirsiniz. Örneğin,

@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);
    }
}

1
Ctx.close () kullanırsam; Sonunda System.exit (n) 'i çağırmaya gerek yok değil mi? context close () içinde System.exit () olmalıdır?
Denys

2
@Denys Hayır, bağlam kapanırken java işleminden çıkmıyor. Örneğimdeki çıkış sadece nasıl ExitCodeGeneratorkullanılabileceğini gösteriyor. mainNazikçe çıkmak için yöntemden dönebilirsiniz (çıkış kodu 0).
Sotirios Delimanolis

79

İlkbahar önyükleme uygulamasında bunun gibi bir şey kullanabilirsiniz

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);
    }
}

16
ApplicationContextOtomatik olarak diğer çekirdeklere enjekte edilebileceğini göstermek için oy verin .
Anthony Chuinard

1
@snovelli kapatma yöntemi nasıl başlatılır? başlatmaKapatma (x), x = 0?
StackOverFlow

Koşullu kapatma olduğunda, bu yürütülebilir. SpringApplication.run (..). Close () program tamamlandıkça yapacaktır.
Abubacker Siddik

neden SpringApplication. (appContext, () -> returnCode); neden appContext.close (). fark ne ?
Rams

@StackOverFlow Çekirdeği ihtiyacınız olan yere enjekte etmeniz ve ardından doğru şekilde kapatılıyorsa önerdiğiniz gibi (x = 0) dönüş kodunu iletmeniz gerekir. Örneğin, Kapatma Yöneticisini bir RestController'a enjekte edebilir ve uzaktan kapatmaya izin verebilir ya da aşağı akış hizmetlerinin eksik olması durumunda JVM'yi kapatacak bir sağlık denetimi izlemesine enjekte edebilirsiniz
snovelli

36

Bu işler, hatta yapılır basılmıştır.

  SpringApplication.run(MyApplication.class, args).close();
  System.out.println("done");

Yani .close()sonra eklemekrun()

Açıklama:

public ConfigurableApplicationContext run(String... args)

Spring uygulamasını çalıştırın, yeni bir ApplicationContext oluşturun ve yenileyin. Parametreler:

args - uygulama argümanları (genellikle bir Java ana yönteminden geçirilir)

Döndürür: çalışan bir ApplicationContext

ve:

void close()Uygulamanın tutabileceği tüm kaynakları ve kilitleri serbest bırakarak bu uygulama bağlamını kapatın. Bu, önbelleğe alınmış tüm tekil çekirdeklerinin yok edilmesini içerir. Not: Bir üst bağlamda close çağırmaz; üst bağlamların kendi bağımsız yaşam döngüleri vardır.

Bu yöntem, yan etkiler olmaksızın birden çok kez çağrılabilir: Zaten kapalı bir bağlamda sonraki yakın çağrılar dikkate alınmaz.

Yani temelde, ana bağlamı kapatmayacak, bu yüzden VM kapanmıyor.


2
Bu çözümün toplu iş gibi kısa ömürlü süreçler için işe yaradığını ancak bunu Spring MVC uygulamalarında kullanmayın. Uygulama, önyüklemeden sonra kapanıyor.
Michael COLL

@MichaelCOLL soru, türü ne olursa olsun bir yay önyükleme uygulamasının programlı olarak nasıl kapatılacağıyla ilgili. Aynı zamanda Spring MVC için de çalışıyor
ACV

1
@ACV Haklısın, işe yarıyor, çok iyi çalışıyor. Ancak ayakta kalması gereken bir uygulama için (Spring MVC uygulaması gibi), bunu yapmanın iyi bir yolu olmadığını düşünüyorum. Benim durumumda kullandım SpringApplication.exit(appContext, () -> returnCode).
Michael COLL

1
Son satırınızda hangi sanal makineden bahsediyorsunuz? Spring Boot uygulamanızı ile başlatıyorsanız SpringApplication.run(MyApplication.class, args), üst bağlam yoktur. Sadece bir bağlam vardır, bağlam yaratılır ve geri döner run, o zaman bunu hemen yaparsınız close. @Michael haklı. Bu, çoğu program olan Bahar bağlamı başlatıldıktan sonra herhangi bir şey yapması gereken programlar için çalışmayacaktır.
Kurtarıcı

@Savior JVM. Bir ana bağlam var. Burada bir Spring boot uygulamasının nasıl kapatılacağından bahsediyoruz. Normalde web uygulamalarını bu şekilde kapatmazsınız. Dolayısıyla bu mekanizma genellikle bir şeyler yapan ve daha sonra durması gereken kısa ömürlü uygulamalar için kullanılır. Varsayılan olarak, Spring boot, siz toplu işlemeyi bitirdikten sonra bile çalışmaya devam eder, bu yüzden bu mekanizmayı kullanmak isteyeceğiniz yer burasıdır.
ACV

3

Uygulamada kullanabilirsiniz SpringApplication. Bu, exit()iki bağımsız değişken alan statik bir yönteme sahiptir: ApplicationContextve bir ExitCodeGenerator:

yani bu yöntemi beyan edebilirsiniz:

@Autowired
public void shutDown(ExecutorServiceExitCodeGenerator exitCodeGenerator) {
    SpringApplication.exit(applicationContext, exitCodeGenerator);
}

Entegrasyon testlerinin içine@DirtiesContext , sınıf düzeyinde not ekleyerek bunu başarabilirsiniz :

  • @DirtiesContext(classMode=ClassMode.AFTER_CLASS) - İlişkili ApplicationContext, test sınıfından sonra kirli olarak işaretlenecektir.
  • @DirtiesContext(classMode=ClassMode.AFTER_EACH_TEST_METHOD) - İlişkili ApplicationContext, sınıftaki her test yönteminden sonra kirli olarak işaretlenecektir.

yani

@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 {
...

Tamam. ExecutorServiceExitCodeGenerator'ı nereden edinmeliyim? Fasulye ise, yaratım pasajı kodunu (ve hangi sınıftan oluşturulduğunu) gösterebilir misiniz? ShutDown (ExecutorServiceExitCodeGenerator exitCodeGenerator) yöntemi hangi sınıfta konulmalıdır?
Vlad G.

2

Bu, SpringBoot uygulamasının düzgün bir şekilde kapatılmasını ve kaynakların işletim sistemine geri verilmesini sağlayacaktır.

@Autowired
private ApplicationContext context;

@GetMapping("/shutdown-app")
public void shutdownApp() {

    int exitCode = SpringApplication.exit(context, (ExitCodeGenerator) () -> 0);
    System.exit(exitCode);
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.