«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

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

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

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

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

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

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

2.3. @Qualifier

Мы используем @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

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

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

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

2.5. @Value

Мы можем использовать @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.

engine.fuelType=petrol

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

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

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

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

2.6. @DependsOn

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

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

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

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

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

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

2.7. @Lazy

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

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

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

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

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

@Configuration
@Lazy
class VehicleFactoryConfig {

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

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

Для получения дополнительной информации посетите веб-сайт эта статья.

2.8. @Lookup

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

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

2.9. @Primary

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

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

@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;
}

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

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

2.10. @Scope

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

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

Например:

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

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

3.1. @Profile

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

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

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

3.2. @Import

@Import(VehiclePartSupplier.class)
class VehicleFactoryConfig {}

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

3.3. @ImportResource

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

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

3.4. @PropertySource

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

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

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

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

~ ~~ 3.5. @PropertySources

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

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

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

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

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

Next »

Spring Web Annotations