Статьи

Spring @Lazy аннотации варианты использования

Среда Spring без особых усилий может решить для вас многие типичные проблемы программирования, но некоторые ее функции менее известны, чем другие. В этом посте мы подробно рассмотрим аннотацию @Lazy , которая принадлежит этой группе. Прочитав несколько примеров, вы сможете применить аннотацию к своим ежедневным задачам разработки.

1. @ Ленивая инициализация bean

Поведение Spring по умолчанию заключается в создании всех определенных bean-компонентов при запуске приложения. Если учесть тот факт, что такая инициализация может занимать довольно много времени, кажется разумным выполнить тяжелые операции, прежде чем пользователи начнут обременять наш сервер.

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

Как сделать боб ленивым? В зависимости от того, как объявлен такой бин, есть два варианта. Если объявление находится в классе @Configuration с использованием аннотации @Bean , вам просто нужно пометить ее аннотацией @Lazy :

01
02
03
04
05
06
07
08
09
10
@Configuration
class SomeConfig {
 
   @Lazy
   @Bean
   LazyResource lazyResource() {
       return new LazyResource();
   }
 
}

Если компонент использует одну из аннотаций компонента и обнаруживается процессом сканирования компонента, аннотацию @Lazy можно использовать непосредственно в классе компонента:

1
2
3
4
5
@Lazy
@Component
class LazyResource {
   //...
}

@Lazy также можно использовать непосредственно в классе @Configuration . В этом случае все объекты @Bean, определенные в классе, инициализируются лениво.

Стоит помнить, что пометка бина @Lazy не означает, что его зависимости также лениво инициализируются. Если вы заинтересованы в инициализации ленивых графов, вы можете добиться этого с…

2. @Lazy инъекция — задержка создания бина до первого использования

Наряду с определениями бинов аннотацию @Lazy можно также использовать для точек внедрения, таких как конструкторы, параметры конструктора, поля и сеттеры . Ниже приведен пример отложенного внедрения целого конструктора ( аннотация @Autowired опущена, так как больше не требуется, начиная с Spring 4.3 ), что означает, что аннотация затронет все определенные зависимости.

01
02
03
04
05
06
07
08
09
10
11
@Component
class RootResource {
 
   private final ResourceDependency dependency;
 
   @Lazy
   RootResource(ResourceDependency dependency) {
       this.dependency = dependency;
   }
 
}

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

Важно понимать, что если отношение помечено @Lazy, это не означает, что создание зависимого компонента откладывается. Когда зависимый бин не помечен самим @Lazy , он будет охотно создан контейнером Spring. Такое поведение приводит к выводу, что ленивая инъекция должна в основном использоваться вместе с ленивой инициализацией .

Давайте рассмотрим пример, в котором есть два связанных bean-компонента. Первый боб помечен @Lazy :

1
2
3
4
5
@Lazy
@Component
class LazyResource {
   //...
}

Другой bean-компонент, который активно инициализируется, зависит от первого, но точка внедрения помечается как @Lazy:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
@Component
class RootResource {
 
   private final LazyResource dependency;
 
   @Lazy
   RootResource(LazyResource dependency) {
       this.dependency = dependency;
   }
 
   void useLazyDependency() {
       dependency.use();
   }
 
}

В описанном сценарии при создании нового экземпляра класса RootResource его зависимость не инициализируется. Новый экземпляр LazyResource создается, когда это действительно необходимо . В этом примере это момент, когда метод useLazyDependency () вызывается впервые. Удалив @Lazy из конструктора RootResource , инициализация компонента LazyResource должна быть выполнена до внедрения.

3. Решение круговых зависимостей с помощью инжекции @Lazy

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

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

1
2
3
4
5
6
The dependencies of some of the beans in the application context form a cycle:
┌─────┐
|  peerResource defined in file [...\dolszewski\blog\PeerResource.class]
↑     ↓
|  someResource defined in file [...\dolszewski\blog\SomeResource.class]
└─────┘

Чтобы решить проблему, бины не должны быть ленивыми инициализированными. Аннотация @Lazy требуется только в одной из точек ввода. Тот, который отмечает его зависимость как ленивый, будет создан первым.

4. Стремитесь к бобам с помощью @Lazy (false)

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

Ваша вторая мысль может заключаться в том, что использование @Lazy (false) на самом деле бесполезно, поскольку вы можете просто удалить аннотацию, чтобы добиться того же, верно? Если вы рассматриваете простое поведение Spring по умолчанию, это абсолютно правильно, но жизнь не всегда так проста.

Когда запуск вашего приложения очень медленный, вы можете рассмотреть ленивую инициализацию для всех управляемых bean-компонентов, чтобы улучшить ваш опыт разработки. Тем не менее, иногда существуют бины, которые всегда нужно инициализировать, даже если активная инициализация была глобально отключена с помощью @ComponentScan (lazyInit = true) . Вот когда приходит @Lazy (false) .

1
2
3
4
5
@Lazy(false)
@Component
class AlwaysEagerResource {
   //...
}

Вывод

Ознакомление с аннотацией @Lazy не требует больших усилий, так как принимает только один атрибут и может применяться только в нескольких местах. Однако, учитывая его несколько применений, стоит знать о его существовании. Если вы найдете статью полезной, пожалуйста, поделитесь ею с коллегами и коллегами. Знаете ли вы какие-нибудь полезные трюки, в которых @Lazy играет одну из главных ролей? Если вы это сделаете, не стесняйтесь помещать их в комментарии.

Смотрите оригинальную статью здесь: Spring @Lazy аннотации сценариев использования

Мнения, высказанные участниками Java Code Geeks, являются их собственными.