Программное закрытие приложения Spring Boot

110

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

В других произведениях то, что противоположно

new SpringApplication(Main.class).run(args);
Аксель Фонтен
источник
1
Хорошая точка зрения! Вызов функции close () должен сработать.
Axel Fontaine
Возможный дубликат Как правильно завершить работу приложения Spring Boot?
Ананд Варки Филипс
@AnandVarkeyPhilips Нет, определенно не так. Этот посвящен API, а другой способ сделать это оператором.
Axel Fontaine
Хорошо .. Эта ссылка на вопрос может помочь другим. Вы хотите, чтобы я удалил вышеуказанный комментарий?
Ананд Варки Филипс

Ответы:

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) в конце, верно? context close () должен иметь внутри System.exit ()?
Денис
2
@Denys Нет, контекст не завершает java-процесс при закрытии. Выход в моем примере просто демонстрирует, как ExitCodeGeneratorможно использовать. Вы можете просто вернуться из mainметода для корректного выхода (код выхода 0).
Сотириос Делиманолис
79

В приложении с весенней загрузкой вы можете использовать что-то вроде этого

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);
    }
}
Snovelli
источник
16
Проголосовать за то, чтобы показать, что ApplicationContextможно автоматически вводить в другие beans.
Anthony Chuinard
1
@snovelli как вызвать метод инициирования выключения? initiateShutdown (x), x = 0?
StackOverFlow
Когда есть условное завершение работы, это может быть выполнено. SpringApplication.run (..). Close () будет работать по завершении программы.
Abubacker Siddik
почему SpringApplication. (appContext, () -> returnCode); почему не может appContext.close (). в чем разница ?
Rams
@StackOverFlow Вам нужно ввести bean-компонент там, где он вам нужен, а затем передать код возврата, как вы предложили (x = 0), если он завершает работу правильно. Например, вы можете внедрить Shutdown Manager в 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()Закройте этот контекст приложения, освободив все ресурсы и блокировки, которые может удерживать реализация. Это включает в себя уничтожение всех кэшированных одноэлементных bean-компонентов. Примечание. Не вызывает закрытие родительского контекста; родительские контексты имеют свой собственный независимый жизненный цикл.

Этот метод можно вызывать несколько раз без побочных эффектов: последующие вызовы закрытия в уже закрытом контексте будут игнорироваться.

По сути, он не закрывает родительский контекст, поэтому виртуальная машина не закрывается.

ACV
источник
2
Напоминаем, что это решение работает для краткосрочных процессов, таких как пакетная обработка, но не используйте его в приложениях Spring MVC. Приложение просто выключилось после загрузки.
Майкл
@MichaelCOLL вопрос о том, как программно закрыть приложение Spring Boot независимо от типа. Это также работает для Spring MVC
ACV
1
@ACV Вы правы, все работает, работает очень хорошо. Но для приложения, которое должно работать (например, приложения Spring MVC), я думаю, это не лучший способ сделать это. В моем случае я использовал SpringApplication.exit(appContext, () -> returnCode).
Майкл
1
Какую виртуальную машину вы имеете в виду в своей последней строке? Если вы запускаете приложение Spring Boot с SpringApplication.run(MyApplication.class, args), родительский контекст отсутствует. Есть только один контекст, контекст, созданный и возвращенный run, который вы затем немедленно close. @ Майкл прав. Это не сработает для программ, которым нужно что-либо делать после инициализации контекста Spring, а это большинство программ.
Спаситель
@Savior JVM. Есть родительский контекст. Здесь мы говорим о том, как закрыть загрузочное приложение Spring. Обычно таким образом не закрывают веб-приложения. Таким образом, этот механизм обычно используется для недолговечных приложений, которые что-то делают, а затем нужно остановить. По умолчанию загрузка Spring будет продолжать работать даже после завершения пакетной обработки, поэтому вы захотите использовать этот механизм именно здесь.
ACV
3

В приложении можно использовать SpringApplication. У этого есть статический exit()метод, который принимает два аргумента: ApplicationContextи 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? Если это bean-компонент, можете ли вы показать код создания фрагмента (и из какого класса он создан)? В какой класс ставить метод 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);
}
Самим Афтаб Ахмед
источник