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

SpringApplication

Клас SpringApplication передбачає зручний спосіб завантаження програми Spring, який запускається з методу main(). У багатьох випадках можна делегувати повноваження статичного методу SpringApplication.run, як це показано в наступному прикладі:

Java
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class MyApplication {
    public static void main(String[] args) {
        SpringApplication.run(MyApplication.class, args);
    }
}
Kotlin
import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.boot.runApplication
@SpringBootApplication
class MyApplication
fun main(args: Array<String>) {
    runApplication<MyApplication>(*args)
}

При запуску програми маєш побачити щось схоже на наступний результат:

 .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::                (v2.7.5)
2022-10-20 12:40:17.841  INFO 16284 --- [           main] o.s.b.d.f.s.MyApplication                : Starting MyApplication використовуючи Java 1.8.0_345 on myhost with PID 16284 (/opt/apps/myapp.jar started by myuser in /opt/apps/)
2022-10-20 12:40:17.849  INFO 16284 --- [           main] o.s.b.d.f.s.MyApplication                : No active profile set, falling back to 1 default profile: "default"
2022-10-20 12:40:20.443  INFO 16284 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat initialized with port(s): 8080 (http)
2022-10-20 12:40:20.455  INFO 16284 --- [           main] o.apache.catalina.core.StandardService   : Starting service [Tomcat]
2022-10-20 12:40:20.455  INFO 16284 --- [           main] org.apache.catalina.core.StandardEngine  : Starting Servlet engine: [Apache Tomcat/9.0.68]
2022-10-20 12:40:20.716  INFO 16284 --- [           main] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring embedded WebApplicationContext
2022-10-20 12:40:20.716  INFO 16284 --- [           main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 2566 ms
2022-10-20 12:40:22.045  INFO 16284 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8080 (http) with context path ''
2022-10-20 12:40:22.073  INFO 16284 --- [           main] o.s.b.d.f.s.MyApplication                : Started

За замовчуванням відображаються повідомлення журналу рівня INFO, включно з деякими важливими відомостями про запуск, такі як користувач, який запустив програму. Якщо необхідний рівень ведення журналу, відмінний від INFO, можна встановити його, як описано в розділі "Рівні ведення логу". Версія програми визначається за версією реалізації з пакета основного класу програми. Журнал введення інформації про запуск можна вимкнути, встановивши spring.main.log-startup-info у false. Це також відключить журналювання активних профілів програми.

Щоб додати додаткове журналювання під час запуску, можна перевизначити logStartupInfo(boolean) у підкласі SpringApplication.

Збій під час запуску

Якщо твою програму не вдається запустити, зареєстровані FailureAnalyzers передають спеціальне повідомлення про помилку і роблять конкретну дію усунення проблеми. Наприклад, якщо вебдодаток запускається через порт 8080, але цей порт вже використовується, з'явиться щось схоже на таке повідомлення:

***************************
APPLICATION FAILED TO START
***************************
Description:
Embedded servlet container failed to start. Port 8080 був already in use.
Action:
Визначити і скасувати процес, який знаходиться на порту 8080 або налаштовує цей параметр для перегляду на іншому порту.
Spring Boot передбачає безліч реалізацій FailureAnalyzer, але ти можеш додати власну.

Якщо жоден із аналізаторів збоїв не в змозі обробити виняток, все одно можна вивести повний звіт про умови, щоб краще розуміти, що саме пішло не так. Для цього необхідно активувати налагодження або активувати логування на рівні debug для org.springframework.boot.autoconfigure.logging.ConditionEvaluationReportLoggingListener.

Наприклад, якщо програма запускається за допомогою java-jar, можна активувати властивість debug таким чином:

$java -jar myproject-0.0. 1-SNAPSHOT.jar --debug

Відкладена ініціалізація

SpringApplication дозволяє ініціалізувати програму у відкладеному режимі. Якщо активізовано відтерміновану ініціалізацію, біни створюються за необхідності, а не під час запуску програми. Як наслідок, активація відкладеної ініціалізації може скоротити час запуску програми. У вебдодатку активація відкладеної ініціалізації призводить до того, що багато пов'язаних з вебдодатком бінів не ініціалізуватимуться до отримання HTTP-запиту.

Недоліком відкладеної ініціалізації є те, що вона може викликати затримку виявлення проблеми в додатку. Якщо неправильно налаштований бін ініціалізується у відкладеному режимі, збій більше не відбуватиметься під час запуску, а проблема стане очевидною лише після ініціалізації біна. Також необхідно переконатися, що JVM має достатньо пам'яті для розміщення всіх бінів програми, а не лише тих, що ініціалізуються під час запуску. З цих причин відкладена ініціалізація не активована за замовчуванням, і рекомендується виконати тонке налаштування розміру купи JVM перед активацією відкладеної ініціалізації.

Відкладену ініціалізацію можна активувати програмно, використовуючи метод lazyInitialization у SpringApplicationBuilder або метод setLazyInitialization у SpringApplication. До того ж, її можна активувати за допомогою властивості spring.main.lazy-initialization, як показано в наступному прикладі:

Properties
spring.main.lazy-initialization=true
Yaml
spring: main: lazy-initialization: true
Якщо необхідно відключити відкладену ініціалізацію для певних бінів, але водночас використовувати відкладену ініціалізацію для решти програми, можна явно встановити їх атрибут "lazy" в false за допомогою анотації @Lazy(false).

Налаштування банера

Банер, який виводиться під час запуску, можна змінити, додавши файл banner.txt у classpath або встановивши властивість spring.banner.location для розташування такого файлу. Якщо файл має кодування, відмінне від UTF-8, можна встановити spring.banner.charset. Крім текстового файлу, можна також додати файл зображення banner.gif, banner.jpg або banner.png до classpath або встановити властивість spring.banner.image.location. Зображення перетворюються на графічне представлення ASCII і виводяться над будь-яким текстовим банером.

У файлі banner.txt можна використовувати будь-який ключ, доступний у Environment, а також будь-який з наступних плейсхолдерів:

Таблиця 1. Змінні банера
Змінна Опис

${application.version}

Номер версії вашої програми, оголошений у MANIFEST.MF. Наприклад, Implementation-Version: 1.0 виводиться як 1.0.

$ {application.formatted-version}

Номер версії твоєї програми, оголошений у MANIFEST.MF і відформатований для виведення на екран (оточений дужками та має префікс v). Наприклад, (v1.0).

${spring-boot.version}

Версія Spring Boot, яку ви використовуєте. Наприклад, 2.7.5.

${spring-boot.formatted-version}

Версія Spring Boot, яку ти використовуєш, відформатована для виведення на екран (оточена дужками і має префікс v). Наприклад, (v2.7.5).

${Ansi.NAME} (or ${AnsiColor.NAME}, ${AnsiBackground.NAME}, ${AnsiStyle.NAME})

Де NAME — ім'я кодування ANSI. Докладніше див. у розділі AnsiPropertySource.

${application.title}

Назва вашої програми, оголошена в MANIFEST.MF. Наприклад, Implementation-Title: MyApp виводиться як MyApp.

Метод SpringApplication.setBanner(…) можна використовувати, якщо потрібно згенерувати банер програмно. Використовуй інтерфейс org.springframework.boot.Banner та реалізуй власний метод printBanner().

Також можна використовувати властивість spring.main .banner-mode, щоб визначити, чи банер повинен виводитися на System.out(console), відправлятися в налаштований диспетчер журналювання (log) або не виводитися взагалі (off).

Виведений банер реєструється як бін-одинак під наступним ім'ям: springBootBanner.

Властивості ${application.version} та ${application.formatted-version} доступні тільки у випадку, якщо ти використовуєш засоби запуску Spring Boot. Значення не будуть дозволені, якщо виконується розпакований jar-файл, і він запускається через java-cp <classpath> <mainclass>.

Саме тому ми рекомендуємо завжди запускати розпаковані jar-файли через java org.springframework.boot.loader.JarLauncher. Це ініціалізує змінні банера application.* перед створенням classpath і запуском твоєї програми.

Налаштування SpringApplication

Якщо налаштування SpringApplication за замовчуванням не відповідають твоїм уподобанням, можна створити локальний екземпляр і налаштувати його. Наприклад, щоб вимкнути банер, можна написати:

Java

import org.springframework.boot.Banner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class MyApplication {
    public static void main(String[] args) {
        SpringApplication application = new SpringApplication(MyApplication.class);
        application.setBannerMode(Banner.Mode.OFF);
        application.run(args);
    }
}
Kotlin

import org.springframework.boot.Banner
import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.boot.runApplication
@SpringBootApplication
class MyApplication
fun main(args: Array<String>) {
    runApplication<MyApplication>(*args) {
        setBannerMode(Banner.Mode.OFF)
    }
}
Аргументи конструктора, що передаються SpringApplication, є конфігураційними джерелами для бінів Spring. У більшості випадків це посилання на класи, позначені анотацією @Configuration, але це можуть бути і прямі посилання на класи з анотацією @Component.

Також можна конфігурувати SpringApplication за допомогою файлу application.properties.

Поточний API засоби складання

Якщо тобі необхідно побудувати ієрархію ApplicationContext (кілька контекстів з батьківськими/дочірніми стосунками) або якщо ти віддаєш перевагу використанню "текучого" API засобу складання, то можна використовувати SpringApplicationBuilder.

SpringApplicationBuilder дозволяє об'єднувати в ланцюжок кілька викликів методів і включає parent та child методи, які дозволяють створювати ієрархію, як показано в наступному прикладі:

Java

new SpringApplicationBuilder()
        .sources(Parent.class)
        .child(Application.class)
        .bannerMode(Banner.Mode.OFF)
        .run(args); 
Kotlin

SpringApplicationBuilder()
        .sources(Parent::class.java)
        .child(Application:: class.java)
        .bannerMode(Banner.Mode.OFF)
        .run(*args) 
Існують деякі обмеження під час створення ієрархії ApplicationContext. Наприклад, вебкомпоненти мають обов'язково утримуватися в дочірньому контексті, а те саме Environment використовується як для батьківського, так і для дочірнього контекстів.

Доступність програм

При розгортанні на платформах програми можуть передавати платформі інформацію про свою доступність, використовуючи таку інфраструктуру, як проби Kubernetes. Spring Boot містить вбудовану підтримку станів доступності, що широко використовуються, "liveness (працездатність)" і "readyiness (готовність)". Якщо ти використовуєш засоби підтримки "актуатора (actuator)" в Spring Boot, то ці стани відображаються як групи кінцевих точок стану програми у власні біни.

Стан працездатності (Liveness)

Стан “Liveness” програми говорить про те, чи дозволяє його внутрішній стан працювати йому правильно або відновлюватися самостійно, якщо він зараз працює з помилками. Порушений стан "Liveness" означає, що програма знаходиться в стані, з якого вона не може відновитися, і інфраструктура повинна перезапустити програму.

Загалом, стан "Liveness" не повинен ґрунтуватися на зовнішніх перевірках, таких як перевірка стану програми. У цьому випадку збій зовнішньої системи (бази даних, веб API, зовнішнього кешу) викликав би масові перезавантаження і каскадні збої по всій платформі.

Внутрішній стан додатків Spring Boot переважно представлений у ApplicationContext для Spring. Якщо контекст програми запустився успішно, Spring Boot передбачає, що програма знаходиться в допустимому стані. Додаток вважається працюючим одразу ж після оновлення контексту.

Стан готовності (Readiness)

Стан "Readiness" програми говорить про те, чи готовий додаток до обробки трафіку. Несправний стан "Readiness" повідомляє платформі, що поки не слід спрямовувати трафік додатку. Зазвичай це відбувається при запуску, під час обробки компонентів CommandLineRunner та ApplicationRunner або в будь-який інший час, якщо програма вирішить, що вона занадто зайнята для обробки додаткового трафіку.

Додаток вважається готовим одразу ж після виклику засобів виконання програми та командного рядка.

Завдання, виконання яких очікується під час запуску, повинні виконуватися компонентами CommandLineRunner та ApplicationRunner замість використання зворотних викликів життєвого циклу компонентів Spring, таких як @PostConstruct.

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

Компоненти програми можуть отримувати поточний стан доступності в будь-який час, впровадивши інтерфейс ApplicationAvailability та викликавши його методи. Найчастіше додаткам потрібно прослуховувати оновлення стану або оновлювати стан програми.

Наприклад, можна експортувати стан "Readiness" програми у файл, щоб "exec-проба" Kubernetes змогла "промацати" цей файл:

Java
import org.springframework.boot.availability.AvailabilityChangeEvent;
import org.springframework.boot.availability.ReadinessState;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;
@Component
public class MyReadinessStateExporter {
    @EventListener
    public void onStateChange(AvailabilityChangeEvent<ReadinessState> event) {
        switch (event.getState()) {
            case ACCEPTING_TRAFFIC:
                // видаляємо файл /tmp/healthy
                break;
            case REFUSING_TRAFFIC:
                // видаляємо файл file /tmp/healthy
                break;
        }
    }
}
Kotlin
import org.springframework.boot.availability.AvailabilityChangeEvent
import org.springframework.boot.availability.ReadinessState
import org.springframework.context.event.EventListener
import org.springframework.stereotype.Component
@Component
class MyReadinessStateExporter {
    @EventListener
    fun onStateChange(event: AvailabilityChangeEvent<ReadinessState?>) {
        when (event.state) {
            ReadinessState.ACCEPTING_TRAFFIC -> {
                // видаляємо файл /tmp/healthy
            }
            ReadinessState.REFUSING_TRAFFIC -> {
                // видаляємо файл file /tmp/healthy
            }
            else -> {
                // ...
            }
        }
    }
}

Ми також можемо оновлювати стан програми, якщо програма виходить з ладу і не може відновитися:

Java

import org.springframework.boot.availability.AvailabilityChangeEvent;
import org.springframework.boot.availability.LivenessState;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Component;
@Component
public class MyLocalCacheVerifier {
    private final ApplicationEventPublisher eventPublisher;
    public MyLocalCacheVerifier(ApplicationEventPublisher eventPublisher) {
        this.eventPublisher = eventPublisher;
    }
    public void checkLocalCache() {
        try {
            // ...
        }
        catch (CacheCompletelyBrokenException ex) {
            AvailabilityChangeEvent.publish(this.eventPublisher, ex, LivenessState.BROKEN);
        }
    }
}
Kotlin

import org.springframework.boot.availability.AvailabilityChangeEvent
import org.springframework.boot.availability.LivenessState
import org.springframework.context.ApplicationEventPublisher
import org.springframework.stereotype.Component
@Component
class MyLocalCacheVerifier(private val eventPublisher: ApplicationEventPublisher) {
    fun checkLocalCache() {
        try {
            // ...
        } catch (ex: CacheCompletelyBrokenException) {
            AvailabilityChangeEvent.publish(eventPublisher, ex, LivenessState.BROKEN)
        }
    }
}

Spring Boot передбачає HTTP-проби Kubernetes для перевірки станів "Liveness" та "Readiness" за допомогою актуатора кінцевих точок стану програми.