В этом разделе мы подробно рассмотрим 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 using 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 MyApplication in 4.937 seconds (JVM running for 6.049)

По умолчанию отображаются сообщения журнала уровня 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 was already in use.
Action:
Identify and stop the process that is listening on port 8080 or configure this application to listen on another port.
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, то эти состояния отображаются как группы конечных точек состояния приложения.

Кроме того, данные о состоянии готовности можно получать, внедрив интерфейс ApplicationAvailability в свои собственные бины.

Состояние работоспособности (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:
                // удаляем файл /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 -> {
                // удаляем файл /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" при помощи актуатора конечных точек состояния приложения.