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

Аннотации ядра Spring

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

1. Обзор

Мы можем использовать возможности механизма Spring DI, используя аннотации в пакетах org.springframework.beans.factory.annotation и org.springframework.context.annotation .

Мы часто называем это «основными аннотациями Spring», и мы рассмотрим их в этом руководстве.

2. Аннотации, связанные с DI

2.1. @Autowired

Мы можем использовать @Autowired , чтобы отметить зависимость, которую Spring собирается разрешить и внедрить . Мы можем использовать эту аннотацию с конструктором, сеттером или внедрением поля.

Инъекция конструктора:

class Car {
Engine engine;

@Autowired
Car(Engine engine) {
this.engine = engine;
}
}

Инъекция сеттера:

class Car {
Engine engine;

@Autowired
void setEngine(Engine engine) {
this.engine = engine;
}
}

Полевая инъекция:

class Car {
@Autowired
Engine engine;
}

@Autowired имеет логический аргумент, который называется required со значением по умолчанию true . Он настраивает поведение Spring, когда не находит подходящего bean-компонента для подключения. Когда true , создается исключение, в противном случае ничего не подключается.

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

Начиная с версии 4.3, нам не нужно явно аннотировать конструкторы с помощью @Autowired , если только мы не объявим хотя бы два конструктора.

Для получения более подробной информации посетите наши статьи о @Autowired и внедрении конструктора .

2.2. @Бин

@Bean отмечает фабричный метод, который создает экземпляр Spring bean:

@Bean
Engine engine() {
return new Engine();
}

Spring вызывает эти методы, когда требуется новый экземпляр возвращаемого типа.

Полученный компонент имеет то же имя, что и фабричный метод. Если мы хотим назвать его по-другому, мы можем сделать это с аргументами имени или значения этой аннотации ( значение аргумента является псевдонимом для имени аргумента ) :

@Bean("engine")
Engine getEngine() {
return new Engine();
}

Обратите внимание, что все методы, аннотированные с помощью @Bean , должны находиться в классах @Configuration .

2.3. @Квалификатор

Мы используем @Qualifier вместе с @Autowired для предоставления идентификатора компонента или имени компонента , которые мы хотим использовать в неоднозначных ситуациях.

Например, следующие два bean-компонента реализуют один и тот же интерфейс:

class Bike implements Vehicle {}

class Car implements Vehicle {}

Если Spring нужно внедрить bean-компонент Vehicle , он получит несколько совпадающих определений. В таких случаях мы можем указать имя компонента явно, используя аннотацию @Qualifier .

Использование внедрения конструктора:

@Autowired
Biker(@Qualifier("bike") Vehicle vehicle) {
this.vehicle = vehicle;
}

Использование инъекций сеттера:

@Autowired
void setVehicle(@Qualifier("bike") Vehicle vehicle) {
this.vehicle = vehicle;
}

В качестве альтернативы:

@Autowired
@Qualifier("bike")
void setVehicle(Vehicle vehicle) {
this.vehicle = vehicle;
}

Использование инъекции поля:

@Autowired
@Qualifier("bike")
Vehicle vehicle;

Для более подробного описания, пожалуйста, прочитайте эту статью .

2.4. @Необходимый

@Required в методах установки, чтобы пометить зависимости, которые мы хотим заполнить через XML:

@Required
void setColor(String color) {
this.color = color;
}
<bean class="com.foreach.annotations.Bike">
<property name="color" value="green" />
</bean>

В противном случае будет выброшено исключение BeanInitializationException .

2.5. @Ценность

Мы можем использовать @Value для внедрения значений свойств в bean-компоненты. Он совместим с конструктором, сеттером и внедрением полей.

Инъекция конструктора:

Engine(@Value("8") int cylinderCount) {
this.cylinderCount = cylinderCount;
}

Инъекция сеттера:

@Autowired
void setCylinderCount(@Value("8") int cylinderCount) {
this.cylinderCount = cylinderCount;
}

В качестве альтернативы:

@Value("8")
void setCylinderCount(int cylinderCount) {
this.cylinderCount = cylinderCount;
}

Полевая инъекция:

@Value("8")
int cylinderCount;

Конечно, вводить статические значения бесполезно. Поэтому мы можем использовать строки-заполнители в @Value для связывания значений, определенных во внешних источниках , например, в файлах .properties или .yaml .

Предположим, что у нас есть следующий файл .properties :

engine.fuelType=petrol

Мы можем внедрить значение engine.fuelType следующим образом:

@Value("${engine.fuelType}")
String fuelType;

Мы можем использовать @Value даже со SpEL. Более сложные примеры можно найти в нашей статье про @Value .

2.6. @Зависит от

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

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

Мы можем использовать @DependsOn для зависимого класса, указав имена bean-компонентов зависимостей. Аргумент значения аннотации нуждается в массиве, содержащем имена bean-компонентов зависимостей:

@DependsOn("engine")
class Car implements Vehicle {}

В качестве альтернативы, если мы определяем bean-компонент с аннотацией @Bean , фабричный метод должен быть аннотирован с помощью @DependsOn :

@Bean
@DependsOn("fuel")
Engine engine() {
return new Engine();
}

2.7. @Ленивый

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

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

Эта аннотация ведет себя по-разному в зависимости от того, где именно мы ее размещаем. Можем поставить:

  • аннотированный метод фабрики компонентов @Bean для задержки вызова метода (отсюда и создание компонента)
  • класс @ Configuration и все содержащиеся в нем методы @Bean будут затронуты
  • класс @Component , который не является классом @Configuration , этот bean-компонент будет инициализирован лениво
  • конструктор, сеттер или поле @Autowired для ленивой загрузки самой зависимости (через прокси)

Эта аннотация имеет аргумент с именем value со значением по умолчанию true . Полезно переопределить поведение по умолчанию.

Например, пометка bean-компонентов для быстрой загрузки, когда глобальная настройка имеет значение lazy, или настройка конкретных методов @Bean для быстрой загрузки в классе @Configuration , отмеченном @Lazy :

@Configuration
@Lazy
class VehicleFactoryConfig {

@Bean
@Lazy(false)
Engine engine() {
return new Engine();
}
}

Для дальнейшего чтения, пожалуйста, посетите эту статью .

2.8. @Искать

Метод, аннотированный @Lookup, сообщает Spring, чтобы он возвращал экземпляр возвращаемого типа метода, когда мы его вызываем.

Подробную информацию об аннотации можно найти в этой статье .

2.9. @Начальный

Иногда нам нужно определить несколько bean-компонентов одного типа. В этих случаях внедрение будет неудачным, потому что Spring понятия не имеет, какой компонент нам нужен.

Мы уже видели вариант решения этого сценария: пометить все точки подключения @Qualifier и указать имя нужного компонента.

Однако в большинстве случаев нам нужен конкретный компонент и редко другие. Мы можем использовать @Primary , чтобы упростить этот случай: если мы пометим наиболее часто используемый компонент с помощью @Primary , он будет выбран в неквалифицированных точках внедрения:

@Component
@Primary
class Car implements Vehicle {}

@Component
class Bike implements Vehicle {}

@Component
class Driver {
@Autowired
Vehicle vehicle;
}

@Component
class Biker {
@Autowired
@Qualifier("bike")
Vehicle vehicle;
}

В предыдущем примере автомобиль является основным транспортным средством. Поэтому в классе Driver Spring внедряет компонент Car . Конечно, в бине Biker значение поля Vehicle будет объектом Bike , потому что оно квалифицировано.

2.10. @Сфера

Мы используем @Scope для определения области действия класса @Component или определения @Bean . Это может быть синглтон, прототип, запрос, сеанс, глобальная сессия или некоторая пользовательская область.

Например:

@Component
@Scope("prototype")
class Engine {}

3. Аннотации конфигурации контекста

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

3.1. @Профиль

Если мы хотим, чтобы Spring использовал класс @Component или метод @Bean только тогда, когда активен определенный профиль , мы можем пометить его с помощью @Profile . Мы можем настроить имя профиля с аргументом значения аннотации :

@Component
@Profile("sportDay")
class Bike implements Vehicle {}

Подробнее о профилях можно прочитать в этой статье .

3.2. @Импорт

С помощью этой аннотации мы можем использовать определенные классы @Configuration без сканирования компонентов . Мы можем предоставить этим классам аргумент значения @Import : ``

@Import(VehiclePartSupplier.class)
class VehicleFactoryConfig {}

3.3. @ИмпортРесурс

С помощью этой аннотации мы можем импортировать конфигурации XML . Мы можем указать местоположение XML-файла с помощью аргумента местоположения или его псевдонима, аргумента значения :

@Configuration
@ImportResource("classpath:/annotations.xml")
class VehicleFactoryConfig {}

3.4. @PropertySource

С помощью этой аннотации мы можем определить файлы свойств для настроек приложения :

@Configuration
@PropertySource("classpath:/annotations.properties")
class VehicleFactoryConfig {}

@PropertySource использует функцию повторяющихся аннотаций Java 8, что означает, что мы можем пометить ею класс несколько раз:

@Configuration
@PropertySource("classpath:/annotations.properties")
@PropertySource("classpath:/vehicle-factory.properties")
class VehicleFactoryConfig {}

3.5. @PropertySources

Мы можем использовать эту аннотацию для указания нескольких конфигураций @PropertySource :

@Configuration
@PropertySources({
@PropertySource("classpath:/annotations.properties"),
@PropertySource("classpath:/vehicle-factory.properties")
})
class VehicleFactoryConfig {}

Обратите внимание, что начиная с Java 8 мы можем добиться того же с помощью функции повторяющихся аннотаций, как описано выше.

4. Вывод

В этой статье мы увидели обзор наиболее распространенных аннотаций ядра Spring. Мы увидели, как настроить связывание компонентов и контекст приложения, а также как пометить классы для сканирования компонентов.

Как обычно, примеры доступны на GitHub .