Програмно вимкніть програму Spring Boot


109

Як я можу програмно вимикання Spring завантаження додатків , не вимикаючи віртуальну машину ?

В інших творах те, що протилежне

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

1
Гарна думка! Зателефонувавши до телефону близько (), це повинно зробити роботу.
Аксель Фонтен


@AnandVarkeyPhilips Ні, це точно не так. Цей - про API, інший - про спосіб для операторів.
Аксель Фонтен

Гаразд .. Це посилання на запитання може допомогти іншим. Ви хочете, щоб я видалив вищевказаний коментар?
Anand Varkey Philips

Відповіді:


111

Закрити в SpringApplicationосновному означає закрити основне ApplicationContext. SpringApplication#run(String...)Метод дає вам , що , ApplicationContextяк ConfigurableApplicationContext. Потім ви можете close()це зробити самостійно.

Наприклад,

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

Крім того, ви можете використовувати static SpringApplication.exit(ApplicationContext, ExitCodeGenerator...)хелперний метод, щоб зробити це за вас. Наприклад,

@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 (); немає потреби викликати System.exit (n) наприкінці правильно? контекст close () повинен мати System.exit () всередині?
Денис

2
@Denys Ні, контекст не виходить з процесу java близько. Вихід у моєму прикладі просто демонструє, як ExitCodeGeneratorможна використовувати. Ви можете просто повернутися з mainметоду для виходу витончено (код виходу 0).
Сотіріос

78

У додатку для весняного завантаження ви можете використовувати щось подібне

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
Оновлення для показу, що ApplicationContextможна автоматично вводити іншу квасолю.
Ентоні Чуйнард

1
@snovelli як викликати метод ініціювання відключення? InitiSSutdown (x), x = 0?
StackOverFlow

Коли відбувається умовне відключення, це можна виконати. SpringApplication.run (..). Close () зробить по мірі завершення програми.
Abubacker Siddik

чому SpringApplication. (appContext, () -> returnCode); чому не може appContext.close (). яка різниця ?
Рамс

@StackOverFlow Вам потрібно ввести квасоля там, де вона вам потрібна, а потім передати код повернення, як ви запропонували (x = 0), якщо він вимикається правильно. Наприклад, ви можете ввести Менеджер вимкнення в RestController і дозволити віддалене відключення, або ви можете ввести його в моніторинг перевірки здоров'я, який закрив би JVM у разі відсутності сервісів нижче за течією
snovelli

36

Це працює, навіть зроблено, друкується.

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

Так додавання .close()післяrun()

Пояснення:

public ConfigurableApplicationContext run(String... args)

Запустіть програму Spring, створивши та оновивши новий ApplicationContext. Параметри:

args - аргументи програми (зазвичай передаються з основного методу Java)

Повертає: запущений ApplicationContext

і:

void close()Закрийте цей контекст програми, вивільнивши всі ресурси та блокування, які може містити реалізація. Сюди входить знищення всіх кешованих бобів однотонних. Примітка: не викликає закриття в батьківському контексті; батьківські контексти мають свій, незалежний життєвий цикл.

Цей метод можна викликати кілька разів без побічних ефектів: Наступні закриті дзвінки у вже закритому контексті будуть ігноровані.

Отже, це не закриє батьківський контекст, тому VM не виходить.


2
Нагадування: це рішення працює для короткочасних процесів, таких як пакетний, але не використовуйте це у додатках Spring MVC. Додаток просто вимикається після завантаження.
Майкл КОЛЛ

@MichaelCOLL питання про те, як програматично вимкнути додаток для весняного завантаження незалежно від типу. Він також працює для Spring MVC
ACV

1
@ACV Ви маєте рацію, це працює, працює дуже добре. Але для програми, яка повинна залишатися в стані (наприклад, Spring MVC app), я думаю, це не найкращий спосіб зробити це. У моєму випадку я використав SpringApplication.exit(appContext, () -> returnCode).
Майкл КОЛЛ

1
На який VM ви посилаєтесь у своєму останньому рядку? Якщо ви запускаєте додаток Spring Boot SpringApplication.run(MyApplication.class, args), батьківський контекст не існує. Є лише один контекст, створений і повернутий контекст run, який ви негайно close. @Michael має рацію. Це не спрацює для програм, яким потрібно нічого робити після ініціалізації весняного контексту, що є більшості програм.
Спас

@Savior JVM. Є батьківський контекст. Тут ми говоримо про те, як вимкнути програму Spring boot. Зазвичай ви не вимикаєте веб-додатки таким чином. Тож цей механізм зазвичай використовується для короткочасних додатків, які щось роблять, а потім потрібно припинити. За замовчуванням весняне завантаження буде продовжувати працювати навіть після того, як ви закінчите пакетну обробку, тож саме тут ви хочете використовувати цей механізм.
ACV

3

У додатку ви можете використовувати SpringApplication. У ньому є статичний exit()метод, який бере два аргументи: the ApplicationContextі an ExitCodeGenerator:

тобто ви можете оголосити цей метод:

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

Всередині тестів на інтеграцію ви можете досягти цього, додавши @DirtiesContextанотацію на рівні класу:

  • @DirtiesContext(classMode=ClassMode.AFTER_CLASS) - Асоційований ApplicationContext буде позначений як брудний після тестового класу.
  • @DirtiesContext(classMode=ClassMode.AFTER_EACH_TEST_METHOD) - Асоційований ApplicationContext буде позначений як брудний після кожного методу тестування в класі.

тобто

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

Гаразд. Де мені взяти ExecutorServiceExitCodeGenerator? Якщо це квасоля, чи можете ви показати фрагмент коду створення (і з якого класу він створений)? У якому класі слід поставити метод shutDown (ExecutorServiceExitCodeGenerator exitCodeGenerator)?
Влад Г.

2

Це дозволить переконатися, що програма SpringBoot належним чином закрита, а ресурси повернуті назад в операційну систему,

@Autowired
private ApplicationContext context;

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

    int exitCode = SpringApplication.exit(context, (ExitCodeGenerator) () -> 0);
    System.exit(exitCode);
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.