Аннотация @Autowired в Spring используется для автоматической внедрения зависимостей. Фреймворк Spring основан на инъекции зависимостей, и мы внедряем зависимости классов через файл конфигурации бинов Spring.
Аннотация @Autowired в Spring
Обычно мы указываем детали конфигурации бинов в файле конфигурации Spring и также указываем бины, которые будут внедрены в другие бины, используя атрибут
ref
. Но фреймворк Spring также предоставляет функции автоматической провязки, где нам не нужно явно указывать детали внедрения бинов. Существуют различные способы, с помощью которых мы можем провязать бин Spring.
- провязка по имени – для этого типа провязки используется метод установки для внедрения зависимостей. Также имя переменной должно быть одинаковым в классе, где мы будем внедрять зависимость, и в файле конфигурации бинов Spring.
- autowire по типу – Для этого типа автоматической связки используется тип класса. Таким образом, в файле конфигурации бинов Spring должен быть настроен только один бин этого типа.
- autowire по конструктору – Это практически аналогично автоматической связке по типу, единственное отличие заключается в том, что используется конструктор для внедрения зависимости.
- autowire по автоопределению – Если вы используете Spring 3.0 или более ранние версии, это один из вариантов автоматической связки, доступных вам. Этот вариант использовался для автоматической связки по конструктору или по типу, как определял контейнер Spring. Поскольку у нас уже есть так много вариантов, этот вариант является устаревшим. В этом руководстве я не буду рассматривать этот вариант.
@Autowired
аннотация – Мы можем использовать аннотацию @Autowired Spring для автоматической связки бинов Spring. @Autowired аннотация может быть применена к переменным и методам для автоматической связки по типу. Мы также можем использовать @Autowired аннотацию в конструкторе для автоматической связки по конструктору в Spring. Для работы аннотации @Autowired также необходимо включить аннотационную конфигурацию в файле конфигурации бинов Spring. Это можно сделать с помощью элемента context:annotation-config или путем определения бина типаorg.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor
.@Qualifier
аннотация – Эта аннотация используется для избежания конфликтов при сопоставлении бинов, и мы должны указать имя бина, которое будет использоваться для автосвязывания. Таким образом, мы можем избежать проблем, когда определены несколько бинов одного и того же типа. Эта аннотация обычно работает с аннотацией @Autowired. Для конструкторов с несколькими аргументами мы можем использовать эту аннотацию с именами аргументов в методе.
По умолчанию автосвязывание spring bean отключено. Значение по умолчанию для автосвязывания бинов Spring – «по умолчанию», что означает, что автосвязывание не выполняется. Значение автосвязывания «no» также имеет тот же эффект. Чтобы продемонстрировать использование автосвязывания бинов Spring, давайте создадим простой проект Spring Maven. Наш конечный проект будет выглядеть как на изображении ниже. Давайте рассмотрим каждый из вариантов автосвязывания по очереди. Для этого мы создадим бин модели и класс сервиса, в котором мы внедрим бин модели.
Spring @Autowired Аннотация – Зависимости Maven
Для автосвязывания Spring нам не нужно добавлять дополнительные зависимости. Наш файл pom.xml содержит зависимости основного фреймворка Spring и выглядит следующим образом.
<project xmlns="https://maven.apache.org/POM/4.0.0" xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="https://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.springframework.samples</groupId>
<artifactId>SpringBeanAutowiring</artifactId>
<version>0.0.1-SNAPSHOT</version>
<properties>
<!-- Generic properties -->
<java.version>1.6</java.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<!-- Spring -->
<spring-framework.version>4.0.2.RELEASE</spring-framework.version>
<!-- Logging -->
<logback.version>1.0.13</logback.version>
<slf4j.version>1.7.5</slf4j.version>
</properties>
<dependencies>
<!-- Spring and Transactions -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring-framework.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>${spring-framework.version}</version>
</dependency>
<!-- Logging with SLF4J & LogBack -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>${slf4j.version}</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>${logback.version}</version>
<scope>runtime</scope>
</dependency>
</dependencies>
</project>
Аннотация Spring @Autowired – Модель Bean
Давайте создадим простой Java Bean, названный Employee. У этого бина будет единственное свойство с методами getter и setter. Мы инициализируем значение этого свойства в файле конфигурации бина Spring.
package com.journaldev.spring.autowiring.model;
public class Employee {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
Аннотация Spring @Autowired – Сервисный класс
Создадим наш сервисный класс, в котором мы будем внедрять бин Employee с помощью автосвязывания Spring.
package com.journaldev.spring.autowiring.service;
import com.journaldev.spring.autowiring.model.Employee;
public class EmployeeService {
private Employee employee;
// конструктор используется для автосвязывания по конструктору
public EmployeeService(Employee emp) {
System.out.println("Autowiring by constructor used");
this.employee = emp;
}
// конструктор по умолчанию, чтобы избежать BeanInstantiationException при автосвязывании
// по имени или по типу
public EmployeeService() {
System.out.println("Default Constructor used");
}
// используется для автосвязывания по имени и по типу
public void setEmployee(Employee emp) {
this.employee = emp;
}
public Employee getEmployee() {
return this.employee;
}
}
Переведем текст на русский язык, сохраняя ваши кастомные разделители:
Мы будем использовать тот же сервисный класс для выполнения автоматического связывания Spring по имени, по типу и с использованием конструктора. Метод установки будет использоваться для автоматического связывания Spring по имени и по типу, в то время как внедрение на основе конструктора будет использоваться с атрибутом автоматической проводки конструктора. Когда мы используем автоматическую проводку Spring по имени или по типу, используется конструктор по умолчанию. Вот почему мы явно определили конструктор по умолчанию для бина EmployeeService.
Spring @Autowired Аннотация – Пример автосвязывания по типу
Давайте создадим отдельный класс с аннотацией Spring @Autowired для автосвязывания по типу.
package com.journaldev.spring.autowiring.service;
import org.springframework.beans.factory.annotation.Autowired;
import com.journaldev.spring.autowiring.model.Employee;
public class EmployeeAutowiredByTypeService {
// Аннотация @Autowired для переменной/сеттеров эквивалентна автосвязыванию "по типу"
@Autowired
private Employee employee;
@Autowired
public void setEmployee(Employee emp){
this.employee=emp;
}
public Employee getEmployee(){
return this.employee;
}
}
Обратите внимание, что я аннотировал как переменную Employee, так и ее метод установки аннотацией Spring @Autowired, однако только одного из них достаточно для автоматического связывания бина Spring.
Spring @Autowired Аннотация и @Qualifier Пример проведения проводки бина по конструктору
Давайте создадим еще один сервисный класс, где мы будем использовать аннотацию @Autowired для внедрения через конструктор. Мы также увидим использование аннотации @Qualifier.
package com.journaldev.spring.autowiring.service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import com.journaldev.spring.autowiring.model.Employee;
public class EmployeeAutowiredByConstructorService {
private Employee employee;
// Аннотация @Autowired на конструкторе эквивалентна autowire="constructor"
@Autowired(required=false)
public EmployeeAutowiredByConstructorService(@Qualifier("employee") Employee emp){
this.employee=emp;
}
public Employee getEmployee() {
return this.employee;
}
}
Когда этот бин будет инициализирован фреймворком Spring, для проводки будет использован бин с именем “employee”. Аннотация @Autowired в Spring принимает один аргумент “required”, который является логическим со значением TRUE по умолчанию. Мы можем задать его как “false”, чтобы фреймворк Spring не выбрасывал исключение, если нет подходящего бина для проводки.
Весна@Autowired Аннотация – Файл конфигурации бина Spring
Файл конфигурации бина Spring является основной частью любого приложения Spring, давайте посмотрим, как выглядит наш файл конфигурации бина Spring, а затем мы рассмотрим каждую его часть.
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="https://www.springframework.org/schema/beans"
xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
xmlns:context="https://www.springframework.org/schema/context"
xsi:schemaLocation="https://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd
https://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context-4.0.xsd"
default-autowire="byName" default-autowire-candidates="*" >
<bean name="employee" class="com.journaldev.spring.autowiring.model.Employee">
<property name="name" value="Pankaj"></property>
</bean>
<bean name="employee1" class="com.journaldev.spring.autowiring.model.Employee" autowire-candidate="false">
<property name="name" value="Dummy Name"></property>
</bean>
<!-- autowiring byName, bean name should be same as the property name -->
<bean name="employeeServiceByName" class="com.journaldev.spring.autowiring.service.EmployeeService" autowire="byName" />
<!-- autowiring byType, there should be only one bean definition for the mapping -->
<bean name="employeeServiceByType" class="com.journaldev.spring.autowiring.service.EmployeeService" autowire="byType" />
<!-- autowiring by constructor -->
<bean name="employeeServiceConstructor" class="com.journaldev.spring.autowiring.service.EmployeeService" autowire="constructor" />
<!-- Enable Annotation based configuration -->
<context:annotation-config />
<!-- using @Autowiring annotation in below beans, byType and constructor -->
<bean name="employeeAutowiredByTypeService" class="com.journaldev.spring.autowiring.service.EmployeeAutowiredByTypeService" />
<bean name="employeeAutowiredByConstructorService" class="com.journaldev.spring.autowiring.service.EmployeeAutowiredByConstructorService" />
</beans>
Важные моменты о файле конфигурации бина Spring:
- элемент beans
default-autowire
используется для определения метода автоматической связывания по умолчанию. Здесь я определяю метод автоматического связывания по умолчанию как по имени. - Элемент beans
default-autowire-candidates
используется для предоставления шаблона для имен бинов, которые можно использовать для автоматической связывания. Для простоты я разрешаю, чтобы все определения бинов были пригодны для автоматического связывания, однако если мы можем определить некоторый шаблон для автоматического связывания. Например, если мы хотим, чтобы только определения бинов DAO были пригодны для автоматического связывания, мы можем указать это какdefault-autowire-candidates="*DAO"
. autowire-candidate="false"
используется в определении бина, чтобы сделать его непригодным для автоматического связывания. Это полезно, когда у нас есть несколько определений бинов для одного типа, и мы хотим, чтобы некоторые из них не были автоматически связаны. Например, в вышеприведенных конфигурациях бина Spring бин “employee1” не будет использоваться для автоматического связывания.- атрибут autowire по имени, по типу и конструктору сам по себе понятен, там особо нечего объяснять.
-
context:annotation-config
используется для включения поддержки конфигурации на основе аннотаций. Обратите внимание, что бины employeeAutowiredByTypeService и employeeAutowiredByConstructorService не имеют атрибутов autowire.
Весна @Autowired Аннотация – Тестовая программа
Теперь, когда наше весеннее приложение готово со всеми видами весеннего проволочного монтажа, давайте напишем простую тестовую программу, чтобы увидеть, работает ли оно ожидаемым образом или нет.
package com.journaldev.spring.autowiring.main;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.journaldev.spring.autowiring.service.EmployeeAutowiredByConstructorService;
import com.journaldev.spring.autowiring.service.EmployeeAutowiredByTypeService;
import com.journaldev.spring.autowiring.service.EmployeeService;
public class SpringMain {
public static void main(String[] args) {
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("spring.xml");
EmployeeService serviceByName = ctx.getBean("employeeServiceByName", EmployeeService.class);
System.out.println("Autowiring byName. Employee Name="+serviceByName.getEmployee().getName());
EmployeeService serviceByType = ctx.getBean("employeeServiceByType", EmployeeService.class);
System.out.println("Autowiring byType. Employee Name="+serviceByType.getEmployee().getName());
EmployeeService serviceByConstructor = ctx.getBean("employeeServiceConstructor", EmployeeService.class);
System.out.println("Autowiring by Constructor. Employee Name="+serviceByConstructor.getEmployee().getName());
// печать хэш-кода для подтверждения того, что все объекты разного типа
System.out.println(serviceByName.hashCode()+"::"+serviceByType.hashCode()+"::"+serviceByConstructor.hashCode());
// Тестирование аннотаций @Autowired
EmployeeAutowiredByTypeService autowiredByTypeService = ctx.getBean("employeeAutowiredByTypeService",EmployeeAutowiredByTypeService.class);
System.out.println("@Autowired byType. Employee Name="+autowiredByTypeService.getEmployee().getName());
EmployeeAutowiredByConstructorService autowiredByConstructorService = ctx.getBean("employeeAutowiredByConstructorService",EmployeeAutowiredByConstructorService.class);
System.out.println("@Autowired by Constructor. Employee Name="+autowiredByConstructorService.getEmployee().getName());
ctx.close();
}
}
Программа проста, мы просто создаем контекст весеннего приложения и используем его для получения различных бинов и печати имени сотрудника. Когда мы запускаем вышеуказанное приложение, мы получаем следующий вывод.
Mar 31, 2014 10:41:58 PM org.springframework.context.support.ClassPathXmlApplicationContext prepareRefresh
INFO: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@3fa99295: startup date [Mon Mar 31 22:41:58 PDT 2014]; root of context hierarchy
Mar 31, 2014 10:41:58 PM org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
INFO: Loading XML bean definitions from class path resource [spring.xml]
Default Constructor used
Default Constructor used
Autowiring by constructor used
Autowiring byName. Employee Name=Pankaj
Autowiring byType. Employee Name=Pankaj
Autowiring by Constructor. Employee Name=Pankaj
21594592::15571401::1863015320
@Autowired byType. Employee Name=Pankaj
@Autowired by Constructor. Employee Name=Pankaj
Mar 31, 2014 10:41:58 PM org.springframework.context.support.ClassPathXmlApplicationContext doClose
INFO: Closing org.springframework.context.support.ClassPathXmlApplicationContext@3fa99295: startup date [Mon Mar 31 22:41:58 PDT 2014]; root of context hierarchy
Как вы можете видеть, для автоматического связывания по имени и типу используется конструктор по умолчанию без аргументов для инициализации бина. Для автосвязывания по конструктору используется конструктор на основе параметров. По хэш-коду всех переменных мы подтвердили, что все бины Spring являются разными объектами и не ссылается на один и тот же объект. Поскольку мы удалили “employee1” из списка подходящих бинов для автоматического связывания, не было никаких путаниц в сопоставлении бинов. Если мы удалим autowire-candidate="false"
из определения “employee1”, мы получим следующее сообщение об ошибке при выполнении указанного выше основного метода.
Exception in thread "main" org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'employeeServiceByType' defined in class path resource [spring.xml]: Unsatisfied dependency expressed through bean property 'employee': : No qualifying bean of type [com.journaldev.spring.autowiring.model.Employee] is defined: expected single matching bean but found 2: employee,employee1; nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [com.journaldev.spring.autowiring.model.Employee] is defined: expected single matching bean but found 2: employee,employee1
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireByType(AbstractAutowireCapableBeanFactory.java:1278)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1170)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:537)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:475)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:304)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:228)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:300)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:195)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:700)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:760)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:482)
at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:139)
at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:83)
at com.journaldev.spring.autowiring.main.SpringMain.main(SpringMain.java:12)
Caused by: org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [com.journaldev.spring.autowiring.model.Employee] is defined: expected single matching bean but found 2: employee,employee1
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:967)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:855)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireByType(AbstractAutowireCapableBeanFactory.java:1263)
... 13 more
Это все, что касается аннотации Spring @Autowired и функции автоматического связывания Spring, пожалуйста, загрузите пример проекта по ссылке ниже и проанализируйте его, чтобы узнать больше.
Source:
https://www.digitalocean.com/community/tutorials/spring-autowired-annotation