На додаток до звичайних подій Spring Framework, таких як ContextRefreshedEvent, SpringApplication посилає деякі додаткові події програми.

Деякі події фактично запускаються до створення ApplicationContext, тому не можна реєструвати слухача цих подій як анотацію @Bean. Ти можеш зареєструвати їх за допомогою SpringApplication.addListeners(...) або методу SpringApplicationBuilder.listeners(...).

Якщо потрібно, щоб ці слухачі реєструвалися автоматично, незалежно від способу створення програми, можна додати файл META-INF/spring.factories в проєкт і послатися на слухач(и) за допомогою ключа org.springframework.context.ApplicationListener, як показано в наступному прикладі:

org.springframework.context.ApplicationListener=com.example.project.MyListener

Події програми надсилаються в наступному порядку в міру виконання програми:

  1. Подія ApplicationStartingEvent відправляється на початку виконання, але перед початком будь-якої обробки, за винятком реєстрації слухачів та ініціалізаторів.

  2. Подія ApplicationEnvironmentPreparedEvent відправляється, коли Environment, яке буде використовуватися в контексті, відомо, але перед створенням контексту.

  3. Подія ApplicationContextInitializedEvent відправляється, коли ApplicationContext підготовлений і викликані ApplicationContextInitializers, але перед завантаженням визначень бінів.

  4. Подія ApplicationPreparedEvent відправляється безпосередньо перед початком оновлення, але після завантаження бінів.

  5. Подія ApplicationStartedEvent відправляється після оновлення контексту, але перед тим, як будуть викликані всі засоби виконання програми та командної рядки.

  6. Відразу після цього відправляється подія AvailabilityChangeEvent з LivenessState.CORRECT, щоб позначити, що додаток вважається працюючим.

  7. Подія ApplicationReadyEvent відправляється після виклику будь-якого засобу виконання програм та командного рядка.

  8. Відразу після цього надсилається подія AvailabilityChangeEvent з ReadinessState.ACCEPTING_TRAFFIC, щоб позначити, що програма готова до обробки запитів.

  9. Подія ApplicationFailedEvent відправляється, якщо при запуску виник виняток.

Наведений вище список включає лише події SpringApplicationEvent, які прив'язані до SpringApplication . На додаток до них наступні події також публікуються після ApplicationPreparedEvent і перед ApplicationStartedEvent:

  • Подія WebServerInitializedEvent відправляється після готовності WebServer. ServletWebServerInitializedEvent та ReactiveWebServerInitializedEvent — це варіанти сервлета та реактивного сервера відповідно.

  • Подія ContextRefreshedEvent надсилається, якщо оновлюється ApplicationContext.

Найчастіше немає потреби використовувати події програми, але знати про їх існування може бути корисним. На внутрішньому рівні Spring Boot події використовуються для виконання різних завдань.
Слухачі подій не повинні виконувати потенційно тривалі завдання, оскільки за замовчуванням вони виконуються в одному потоці. Розглянь можливість використання засобів виконання програми та командного рядка натомість.

Події програми відправляються за допомогою механізму публікації подій Spring Framework. Частина цього механізму забезпечує, що подія, опублікована для слухачів у дочірньому контексті, також буде опублікована для слухачів у будь-яких предках. Отже, якщо твоя програма використовує ієрархію екземплярів SpringApplication, слухач може отримати кілька екземплярів одного і того ж типу події програми.

Щоб слухач міг відрізнити подію для свого контексту від події для дочірнього контексту, він повинен зробити запит на впровадження свого контексту програми, а потім порівняти впроваджений контекст із контекстом події. Контекст може бути впроваджений шляхом реалізації ApplicationContextAware або, якщо слухач є біном, за допомогою анотації @Autowired.

Веботочення

SpringApplication намагається створити потрібний тип ApplicationContext за твоєю вказівкою. Для визначення WebApplicationType використовується такий алгоритм:

  • Якщо є Spring MVC, використовується AnnotationConfigServletWebServerApplicationContext

  • Якщо Spring MVC відсутній, а Spring WebFlux присутній, використовується AnnotationConfigReactiveWebServerApplicationContext

  • В іншому випадку використовується AnnotationConfigApplicationContext

Це означає, що якщо ти використовуєш Spring MVC і новий WebClient з Spring WebFlux в одному додатку, Spring MVC буде використовуватися за замовчуванням. Ти можеш легко перевизначити це, викликавши setWebApplicationType(WebApplicationType).

Також можна повністю керувати використовуваним типом ApplicationContext, викликаючи setApplicationContextClass(…) .

Часто бажано викликати setWebApplicationType(WebApplicationType.NONE) при використанні SpringApplication у тесті JUnit.

Доступ до аргументів програми

Якщо необхідно отримати доступ до аргументів програми, які були передані в SpringApplication.run(…), можна впровадити бін org.springframework.boot.ApplicationArguments. Інтерфейс ApplicationArguments надає доступ як до сирих аргументів String[], так і до парсованих аргументів option та non-option, як показано в наступному прикладі:

Java

import java.util.List;
import org.springframework.boot.ApplicationArguments;
import org.springframework.stereotype.Component;
@Component
public class MyBean {
    public MyBean(ApplicationArguments args) {
        boolean debug = args.containsOption("debug");
        List<String> files = args.getNonOptionArgs();
        if (debug) {
            System.out.println(files);
        }
        // якщо запустити з параметром "--debug logfile.txt" option, ["logfile.txt"] will be output.
    }
}
Kotlin

import org.springframework.boot.ApplicationArguments
import org.springframework.stereotype.Component
@Component
class MyBean(args: ApplicationArguments) {
    init {
        val debug = args.containsOption("debug")
        val files = args.nonOptionArgs
        if (debug) {
            println(files)
        }
        // якщо запустити з параметром "--debug logfile.txt", prints ["logfile.txt"].
    }
}
Spring Boot також реєструє CommandLinePropertySource в Environment зі Spring. Це дозволяє також впроваджувати окремі аргументи програми за допомогою анотації @Value.

Використання ApplicationRunner або CommandLineRunner

Якщо необхідно виконати певний код після запуску SpringApplication можна реалізувати інтерфейси ApplicationRunner або CommandLineRunner. Обидва інтерфейси працюють однаково і передбачають один метод run, який викликається безпосередньо перед тим, як SpringApplication.run(…) буде завершено.

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

Інтерфейс CommandLineRunner надає доступ до аргументів програми у вигляді масиву рядків, тоді як ApplicationRunner використовує інтерфейс ApplicationArguments, розглянутий раніше. У наступному прикладі показано CommandLineRunner з методом run:

Java

import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;
@Component
public class MyCommandLineRunner implements CommandLineRunner {
    @Override
    public void run(String... args) {
        // робимо щось...
    }
}
Kotlin

import org.springframework.boot.CommandLineRunner
import org.springframework.stereotype.Component
@Component
class MyCommandLineRunner : CommandLineRunner {
    override fun run(vararg args: String) {
        // робимо щось...
    }
}

Якщо визначено кілька бінів CommandLineRunner або ApplicationRunner, які повинні викликатися в певному порядку, можна додатково реалізувати інтерфейс org.springframework.core.Ordered або використовувати анотацію org.springframework.core.annotation.Order.

Вихід із програми

Кожен SpringApplication реєструє перехоплювач завершення в JVM, щоб забезпечити поетапне закриття ApplicationContext при виході. Можна використовувати всі стандартні зворотні виклики життєвого циклу Spring (наприклад, інтерфейс DisposableBean або анотацію @PreDestroy).

До того ж, біни можуть реалізувати інтерфейс org.springframework.boot.ExitCodeGenerator, якщо їм потрібно повертати певний код виходу під час виклику SpringApplication.exit(). Цей код виходу можна передати в System.exit(), щоб повернути його як код стану, як показано в наступному прикладі:

Java

import org.springframework.boot.ExitCodeGenerator;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
@SpringBootApplication
public class MyApplication {
    @Bean
    public ExitCodeGenerator exitCodeGenerator() {
        return () -> 42;
    }
    public static void main(String[] args) {
        System.exit(SpringApplication.exit(SpringApplication.run(MyApplication.class, args)));
    }
}
Kotlin

import org.springframework.boot.ExitCodeGenerator
import org.springframework.boot.SpringApplication
import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.boot.runApplication
import org.springframework.context.annotation.Bean
import kotlin.system.exitProcess
@SpringBootApplication
class MyApplication {
    @Bean
    fun exitCodeGenerator() = ExitCodeGenerator { 42 }
}
fun main(args: Array<String>) {
    exitProcess(SpringApplication.exit(
        runApplication<MyApplication>(*args)))
}

До того ж, інтерфейс ExitCodeGenerator може бути реалізований винятками. При виникненні такого винятку Spring Boot повертає код виходу, що передається реалізованим методом getExitCode().

Якщо існує більш ніж один ExitCodeGenerator, то використовується перший згенерований ненульовий код виходу. Щоб керувати порядком виклику генераторів, додатково реалізуй інтерфейс org.springframework.core.Ordered або використовуй анотацію org.springframework.core.annotation.Order.

Функції адміністрування

Можна увімкнути функції, пов'язані з адмініструванням, для програми, якщо вказати властивість spring.application.admin.enabled. Це відкриє SpringApplicationAdminMXBean для платформи MBeanServer. Цю функцію можна використовувати для віддаленого адміністрування програми Spring Boot. Ця функція також може бути корисною для будь-якої реалізації служби-обгортки.

Якщо ти хочеш дізнатися, через який HTTP-порт працює програма, отримай властивість із ключем local.server.port.

Відстеження запуску програм

Під час запуску програми SpringApplication та ApplicationContext виконують безліч завдань, що пов'язані з життєвим циклом додатку, життєвим циклом бинів і навіть із обробкою подій додатку. Завдяки ApplicationStartup Spring Framework дозволяє відстежувати послідовність запуску програми за допомогою об'єктів StartupStep. Ці дані можна збирати з метою профілювання або просто для кращого розуміння процесу запуску програми.

Є можливість вибору реалізації ApplicationStartup при налаштуванні екземпляра SpringApplication. Наприклад, щоб використовувати BufferingApplicationStartup, можна написати:

Java

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.metrics.buffering.BufferingApplicationStartup;
@SpringBootApplication
public class MyApplication {
    public static void main(String[] args) {
        SpringApplication application = new SpringApplication(MyApplication.class);
        application.setApplicationStartup(new BufferingApplicationStartup(2048));
        application.run(args);
    }
}
Kotlin

import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.boot.context.metrics.buffering.BufferingApplicationStartup
import org.springframework.boot.runApplication
@SpringBootApplication
class MyApplication
fun main(args: Array<String>) {
    runApplication<MyApplication>(*args) {
        applicationStartup = BufferingApplicationStartup(2048)
    }
}

Перша доступна реалізація, FlightRecorderApplicationStartup, передбачається Spring Framework. Вона додає пов'язані зі Spring події запуску в сесію Java Flight Recorder і призначена для профілювання додатків та приведення життєвого циклу Spring-контексту у відповідність до подій JVM (таких як операції виділення, операції очищення пам'яті від непотрібних даних, завантаження класів...). Після конфігурування можна записувати дані, запустивши програму з активованим Flight Recorder:

$ java -XX:StartFlightRecording:filename=recording.jfr,duration=10s -jar demo.jar

Spring Boot поставляється з варіацією BufferingApplicationStartup; ця реалізація призначена для буферизації етапів запуску та скидання їх у зовнішню систему метрик. Програми можуть вимагати бін типу BufferingApplicationStartup у будь-якому компоненті.

Spring Boot також можна налаштувати так, щоб він відкривав кінцеву точку startup, яка передає цю інформацію у вигляді документа JSON.