Перейти к основному содержимому

Ленивая инициализация в Spring Boot 2

· 4 мин. чтения

1. Обзор

В этом руководстве мы увидим, как настроить ленивую инициализацию на уровне приложения, начиная с Spring Boot 2.2.

2. Ленивая инициализация

По умолчанию в Spring все определенные bean-компоненты и их зависимости создаются при создании контекста приложения.

Напротив, когда мы настраиваем bean-компонент с отложенной инициализацией, bean-компонент будет создан и его зависимости будут внедрены только тогда, когда они потребуются.

3. Зависимость от Maven

Чтобы получить Spring Boot в нашем приложении, нам нужно включить его в наш путь к классам.

С Maven мы можем просто добавить зависимость spring-boot- starter :

<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<version>2.4.3</version>
</dependency>
</dependencies>

4. Включить ленивую инициализацию

Spring Boot 2 представляет свойство spring.main.lazy-initialization , упрощающее настройку отложенной инициализации во всем приложении.

Установка значения свойства в true означает, что все bean-компоненты в приложении будут использовать отложенную инициализацию.

Давайте настроим свойство в нашем конфигурационном файле application.yml :

spring:
main:
lazy-initialization: true

Или, если это так, в нашем файле application.properties :

spring.main.lazy-initialization=true

Эта конфигурация влияет на все bean-компоненты в контексте. Итак, если мы хотим настроить ленивую инициализацию для конкретного компонента, мы можем сделать это с помощью подхода @Lazy .

Более того, мы можем использовать новое свойство в сочетании с аннотацией @Lazy со значением false .

Другими словами, все определенные bean-компоненты будут использовать ленивую инициализацию, за исключением тех, которые мы явно настроили с помощью @Lazy(false) .

4.1. Использование SpringApplicationBuilder

Другой способ настроить ленивую инициализацию — использовать метод SpringApplicationBuilder :

SpringApplicationBuilder(Application.class)
.lazyInitialization(true)
.build(args)
.run();

В приведенном выше примере мы используем метод lazyInitialization , чтобы контролировать, должно ли приложение инициализироваться лениво.

4.2. Использование SpringApplication

В качестве альтернативы мы также можем использовать класс SpringApplication :

SpringApplication app = new SpringApplication(Application.class);
app.setLazyInitialization(true);
app.run(args);

Здесь мы используем метод setLazyInitialization , чтобы настроить ленивую инициализацию нашего приложения.

Важно помнить, что свойства, определенные в файлах свойств приложения, имеют приоритет над флагами, установленными с помощью SpringApplication или SpringApplicationBuilder .

5. Беги

Давайте создадим простой сервис, который позволит нам протестировать то, что мы только что описали.

Добавив сообщение в конструктор, мы будем точно знать, когда будет создан компонент.

public class Writer {

private final String writerId;

public Writer(String writerId) {
this.writerId = writerId;
System.out.println(writerId + " initialized!!!");
}

public void write(String message) {
System.out.println(writerId + ": " + message);
}

}

Кроме того, давайте создадим SpringApplication и внедрим сервис, который мы создали ранее.

@SpringBootApplication
public class Application {

@Bean("writer1")
public Writer getWriter1() {
return new Writer("Writer 1");
}

@Bean("writer2")
public Writer getWriter2() {
return new Writer("Writer 2");
}

public static void main(String[] args) {
ApplicationContext ctx = SpringApplication.run(Application.class, args);
System.out.println("Application context initialized!!!");

Writer writer1 = ctx.getBean("writer1", Writer.class);
writer1.write("First message");

Writer writer2 = ctx.getBean("writer2", Writer.class);
writer2.write("Second message");
}
}

Давайте установим для свойства spring.main.lazy-initialization значение false и запустим наше приложение.

Writer 1 initialized!!!
Writer 2 initialized!!!
Application context initialized!!!
Writer 1: First message
Writer 2: Second message

Как мы видим, bean-компоненты были созданы при запуске контекста приложения.

Теперь давайте изменим значение spring.main.lazy-initialization на true и снова запустим наше приложение.

Application context initialized!!!
Writer 1 initialized!!!
Writer 1: First message
Writer 2 initialized!!!
Writer 2: Second message

В результате приложение создавало bean-компоненты не во время запуска, а только тогда, когда они ему были нужны.

6. Эффекты ленивой инициализации

Включение ленивой инициализации во всем приложении может привести как к положительным, так и к отрицательным последствиям.

Поговорим о некоторых из них, как они описаны в официальном анонсе нового функционала:

  1. Ленивая инициализация может уменьшить количество bean-компонентов, создаваемых при запуске приложения, поэтому мы можем улучшить время запуска приложения.
  2. Поскольку ни один из bean-компонентов не создается до тех пор, пока они не потребуются, мы могли бы замаскировать проблемы, получая их во время выполнения, а не во время запуска.
  3. Проблемы могут включать ошибки нехватки памяти, неправильные конфигурации или ошибки, обнаруженные в определении класса.
  4. Кроме того, когда мы находимся в веб-контексте, создание бина по запросу увеличивает задержку HTTP-запросов — создание бина повлияет только на первый запрос, но это может негативно сказаться на балансировке нагрузки и автоматическом масштабировании .

7. Заключение

В этом руководстве мы настроили ленивую инициализацию с помощью нового свойства spring.main.lazy-initialization, представленного в Spring Boot 2.2.

Как всегда, исходный код этого руководства доступен на GitHub .