- Руководство по Spring @Autowired
- 2. Включение аннотаций @Autowired
- 3. Использование @Autowired
- 3.1. @Autowired в свойствах
- 3.2. @Autowired на сеттерах
- 3.3. @Autowired для конструкторов
- 4. @Autowired и необязательные зависимости
- 5. Автопроводная неоднозначность
- 5.1. Автопроводка @Qualifier
- 5.2. Автопроводка по пользовательскому классификатору
- 5.3. Автопроводка по имени
- 6. Заключение
- Annotation Interface Autowired
- Autowired Constructors
- Autowired Fields
- Autowired Methods
- Autowired Parameters
- Multiple Arguments and ‘required’ Semantics
- Autowiring Arrays, Collections, and Maps
- Not supported in BeanPostProcessor or BeanFactoryPostProcessor
Руководство по Spring @Autowired
Начиная с Spring 2.5, в фреймворке появилась управляемая аннотациями Dependency Injection . Основная аннотация этой функции — @Autowired . Это позволяет Spring разрешать и внедрять сотрудничающие компоненты в наш компонент.
В этом уроке мы сначала рассмотрим, как включить автоподключение и различные способы автоподключения bean-компонентов. После этого мы поговорим о разрешении конфликтов bean-компонентов с помощью аннотации @Qualifier , а также о возможных сценариях исключений.
2. Включение аннотаций @Autowired
Платформа Spring обеспечивает автоматическую инъекцию зависимостей. Другими словами, объявив все зависимости bean-компонентов в файле конфигурации Spring, контейнер Spring может автоматически связывать отношения между взаимодействующими bean-компонентами . Это называется автопроводкой Spring bean .
Чтобы использовать конфигурацию на основе Java в нашем приложении, давайте включим внедрение на основе аннотаций « для загрузки нашей конфигурации Spring:
@Configuration @ComponentScan("com.foreach.autowire.sample") public class AppConfig >
Кроме того, аннотация в основном используется для активации аннотаций внедрения зависимостей в XML-файлах Spring.
Более того, Spring Boot вводит аннотацию @SpringBootApplication . Эта единственная аннотация эквивалентна использованию @Configuration , @EnableAutoConfiguration и @ComponentScan .
Давайте используем эту аннотацию в основном классе приложения:
@SpringBootApplication class VehicleFactoryApplication public static void main(String[] args) SpringApplication.run(VehicleFactoryApplication.class, args); > >
В результате, когда мы запускаем это приложение Spring Boot, оно автоматически сканирует компоненты в текущем пакете и его подпакетах . Таким образом, он зарегистрирует их в контексте приложения Spring и позволит нам внедрять bean-компоненты с помощью @Autowired .
3. Использование @Autowired
После включения внедрения аннотаций мы можем использовать автосвязывание свойств, сеттеров и конструкторов .
3.1. @Autowired в свойствах
Давайте посмотрим, как мы можем аннотировать свойство с помощью @Autowired . Это устраняет необходимость в геттерах и сеттерах.
Во-первых, давайте определим bean-компонент fooFormatter :
@Component("fooFormatter") public class FooFormatter public String format() return "foo"; > >
Затем мы внедрим этот bean-компонент в bean- компонент FooService , используя @Autowired в определении поля:
@Component public class FooService @Autowired private FooFormatter fooFormatter; >
В результате Spring внедряет fooFormatter при создании FooService .
3.2. @Autowired на сеттерах
Теперь давайте попробуем добавить аннотацию @Autowired к методу установки.
В следующем примере метод установки вызывается с экземпляром FooFormatter при создании FooService :
public class FooService private FooFormatter fooFormatter; @Autowired public void setFooFormatter(FooFormatter fooFormatter) this.fooFormatter = fooFormatter; > >
3.3. @Autowired для конструкторов
Наконец, давайте используем @Autowired в конструкторе.
Мы увидим, что экземпляр FooFormatter вводится Spring в качестве аргумента конструктору FooService :
public class FooService private FooFormatter fooFormatter; @Autowired public FooService(FooFormatter fooFormatter) this.fooFormatter = fooFormatter; > >
4. @Autowired и необязательные зависимости
При создании bean-компонента должны быть доступны зависимости @Autowired . В противном случае, если Spring не может разрешить bean-компонент для связывания, он выдаст исключение .
Следовательно, он предотвращает успешный запуск контейнера Spring, за исключением формы:
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [com.autowire.sample.FooDAO] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: @org.springframework.beans.factory.annotation.Autowired(required=true)>
Чтобы исправить это, нам нужно объявить bean-компонент требуемого типа:
public class FooService @Autowired(required = false) private FooDAO dataAccessor; >
5. Автопроводная неоднозначность
По умолчанию Spring разрешает записи @Autowired по типу. Если в контейнере доступно более одного bean-компонента одного типа, фреймворк выдаст фатальное исключение .
Чтобы разрешить этот конфликт, нам нужно явно указать Spring, какой компонент мы хотим внедрить.
5.1. Автопроводка @Qualifier
Например, давайте посмотрим, как мы можем использовать аннотацию @Qualifier для указания требуемого компонента.
Во-первых, мы определим 2 bean-компонента типа Formatter :
@Component("fooFormatter") public class FooFormatter implements Formatter public String format() return "foo"; > >
@Component("barFormatter") public class BarFormatter implements Formatter public String format() return "bar"; > >
Теперь давайте попробуем внедрить bean-компонент Formatter в класс FooService :
public class FooService @Autowired private Formatter formatter; >
В нашем примере для контейнера Spring доступны две конкретные реализации Formatter . В результате Spring выдаст исключение NoUniqueBeanDefinitionException при построении FooService : «
Caused by: org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [com.autowire.sample.Formatter] is defined: expected single matching bean but found 2: barFormatter,fooFormatter
Мы можем избежать этого, сузив реализацию с помощью аннотации @Qualifier :
public class FooService @Autowired @Qualifier("fooFormatter") private Formatter formatter; >
При наличии нескольких bean-компонентов одного типа рекомендуется использовать @Qualifier , чтобы избежать двусмысленности.
Обратите внимание, что значение аннотации @Qualifier совпадает с именем, объявленным в аннотации @Component нашей реализации FooFormatter .
5.2. Автопроводка по пользовательскому классификатору
Spring также позволяет нам создавать собственные аннотации @Qualifier . Для этого мы должны предоставить аннотацию @Qualifier с определением:
@Qualifier @Target( ElementType.FIELD, ElementType.METHOD, ElementType.TYPE, ElementType.PARAMETER>) @Retention(RetentionPolicy.RUNTIME) public @interface FormatterType String value(); >
Затем мы можем использовать FormatterType в различных реализациях, чтобы указать пользовательское значение:
@FormatterType("Foo") @Component public class FooFormatter implements Formatter public String format() return "foo"; > >
@FormatterType("Bar") @Component public class BarFormatter implements Formatter public String format() return "bar"; > >
Наконец, наша пользовательская аннотация квалификатора готова к использованию для автоматического связывания:
@Component public class FooService @Autowired @FormatterType("Foo") private Formatter formatter; >
Значение, указанное в мета-аннотации @Target , ограничивает применение квалификатора, которым в нашем примере являются поля, методы, типы и параметры.
5.3. Автопроводка по имени
Spring использует имя компонента в качестве значения квалификатора по умолчанию. Он будет проверять контейнер и искать bean-компонент с точным именем в качестве свойства для его автоматического связывания.
Следовательно, в нашем примере Spring сопоставляет имя свойства fooFormatter с реализацией FooFormatter . Поэтому он внедряет эту конкретную реализацию при создании FooService :
public class FooService @Autowired private Formatter fooFormatter; >
6. Заключение
В этой статье мы обсудили автопроводку и различные способы ее использования. Мы также рассмотрели способы решения двух распространенных исключений автосвязывания, вызванных либо отсутствующим bean-компонентом, либо неоднозначной инъекцией bean-компонента.
Исходный код этой статьи доступен на проекте GitHub .
Annotation Interface Autowired
Marks a constructor, field, setter method, or config method as to be autowired by Spring’s dependency injection facilities. This is an alternative to the JSR-330 Inject annotation, adding required-vs-optional semantics.
Autowired Constructors
Only one constructor of any given bean class may declare this annotation with the required() attribute set to true , indicating the constructor to autowire when used as a Spring bean. Furthermore, if the required attribute is set to true , only a single constructor may be annotated with @Autowired . If multiple non-required constructors declare the annotation, they will be considered as candidates for autowiring. The constructor with the greatest number of dependencies that can be satisfied by matching beans in the Spring container will be chosen. If none of the candidates can be satisfied, then a primary/default constructor (if present) will be used. Similarly, if a class declares multiple constructors but none of them is annotated with @Autowired , then a primary/default constructor (if present) will be used. If a class only declares a single constructor to begin with, it will always be used, even if not annotated. An annotated constructor does not have to be public.
Autowired Fields
Fields are injected right after construction of a bean, before any config methods are invoked. Such a config field does not have to be public.
Autowired Methods
Config methods may have an arbitrary name and any number of arguments; each of those arguments will be autowired with a matching bean in the Spring container. Bean property setter methods are effectively just a special case of such a general config method. Such config methods do not have to be public.
Autowired Parameters
Although @Autowired can technically be declared on individual method or constructor parameters since Spring Framework 5.0, most parts of the framework ignore such declarations. The only part of the core Spring Framework that actively supports autowired parameters is the JUnit Jupiter support in the spring-test module (see the TestContext framework reference documentation for details).
Multiple Arguments and ‘required’ Semantics
In the case of a multi-arg constructor or method, the required() attribute is applicable to all arguments. Individual parameters may be declared as Java-8 style Optional or, as of Spring Framework 5.0, also as @Nullable or a not-null parameter type in Kotlin, overriding the base ‘required’ semantics.
Autowiring Arrays, Collections, and Maps
In case of an array, Collection , or Map dependency type, the container autowires all beans matching the declared value type. For such purposes, the map keys must be declared as type String which will be resolved to the corresponding bean names. Such a container-provided collection will be ordered, taking into account Ordered and @Order values of the target components, otherwise following their registration order in the container. Alternatively, a single matching target bean may also be a generally typed Collection or Map itself, getting injected as such.
Not supported in BeanPostProcessor or BeanFactoryPostProcessor
Note that actual injection is performed through a BeanPostProcessor which in turn means that you cannot use @Autowired to inject references into BeanPostProcessor or BeanFactoryPostProcessor types. Please consult the javadoc for the AutowiredAnnotationBeanPostProcessor class (which, by default, checks for the presence of this annotation).