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. Эффекты ленивой инициализации
Включение ленивой инициализации во всем приложении может привести как к положительным, так и к отрицательным последствиям.
Поговорим о некоторых из них, как они описаны в официальном анонсе нового функционала:
- Ленивая инициализация может уменьшить количество bean-компонентов, создаваемых при запуске приложения, поэтому мы можем улучшить время запуска приложения.
- Поскольку ни один из bean-компонентов не создается до тех пор, пока они не потребуются, мы могли бы замаскировать проблемы, получая их во время выполнения, а не во время запуска.
- Проблемы могут включать ошибки нехватки памяти, неправильные конфигурации или ошибки, обнаруженные в определении класса.
- Кроме того, когда мы находимся в веб-контексте, создание бина по запросу увеличивает задержку HTTP-запросов — создание бина повлияет только на первый запрос, но это может негативно сказаться на балансировке нагрузки и автоматическом масштабировании .
7. Заключение
В этом руководстве мы настроили ленивую инициализацию с помощью нового свойства spring.main.lazy-initialization,
представленного в Spring Boot 2.2.
Как всегда, исходный код этого руководства доступен на GitHub .