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 .