Guide to Spring @Autowired – 春季指南 @Autowired

最后修改: 2016年 6月 6日

1. Overview

1.概述

Starting with Spring 2.5, the framework introduced annotations-driven Dependency Injection. The main annotation of this feature is @Autowired. It allows Spring to resolve and inject collaborating beans into our bean.

从Spring 2.5开始,该框架引入了注解驱动的依赖注入。该功能的主要注解是@Autowired 它允许Spring解析并将协作的Bean注入我们的Bean中。

In this tutorial, we’ll first take a look at how to enable autowiring and the various ways to autowire beans. Afterward, we’ll talk about resolving bean conflicts using @Qualifier annotation, as well as potential exception scenarios.

在本教程中,我们将首先了解如何启用自动布线以及自动布线Bean的各种 方式。之后,我们将讨论使用@Qualifier注解来解决Bean冲突,以及潜在的异常情况。

2. Enabling @Autowired Annotations

2.启用@Autowired注释

The Spring framework enables automatic dependency injection. In other words, by declaring all the bean dependencies in a Spring configuration file, Spring container can autowire relationships between collaborating beans. This is called Spring bean autowiring.

Spring框架实现了自动依赖性注入。换句话说,通过在Spring配置文件中声明所有的Bean依赖关系,Spring容器可以在合作的Bean之间自动连接关系。这被称为Spring bean autowiring

To use Java-based configuration in our application, let’s enable annotation-driven injection to load our Spring configuration:

为了在我们的应用程序中使用基于Java的配置,让我们启用注解驱动的注入 来加载我们的Spring配置。

@Configuration
@ComponentScan("com.baeldung.autowire.sample")
public class AppConfig {}

Alternatively, the <context:annotation-config> annotation is mainly used to activate the dependency injection annotations in Spring XML files.

另外,<context:annotation-config>注释主要用于激活 Spring XML 文件的依赖注入注释。

Moreover, Spring Boot introduces the @SpringBootApplication annotation. This single annotation is equivalent to using @Configuration, @EnableAutoConfiguration, and @ComponentScan.

此外,Spring Boot引入了@SpringBootApplicationannotation。这个单一的注解等同于使用@Configuration@EnableAutoConfiguration@ComponentScan

Let’s use this annotation in the main class of the application:

让我们在应用程序的主类中使用这个注解。

@SpringBootApplication
public class App {
    public static void main(String[] args) {
        SpringApplication.run(App.class, args);
    }
}

As a result, when we run this Spring Boot application, it will automatically scan the components in the current package and its sub-packages. Thus it will register them in Spring’s Application Context, and allow us to inject beans using @Autowired.

因此,当我们运行这个Spring Boot应用程序时,它将自动扫描当前包及其子包中的组件。因此,它将在Spring的应用上下文中注册它们,并允许我们使用@Autowired注入bean。

3. Using @Autowired

3.使用@Autowired

After enabling annotation injection, we can use autowiring on properties, setters, and constructors.

在启用注解注入后,我们可以在属性、设置器和构造函数上使用自动布线

3.1. @Autowired on Properties

3.1.@Autowired on Properties

Let’s see how we can annotate a property using @Autowired. This eliminates the need for getters and setters.

让我们看看我们如何使用@Autowired来注释一个属性。这消除了对getters和setters的需要。

First, let’s define a fooFormatter bean:

首先,让我们定义一个fooFormatter bean。

@Component("fooFormatter")
public class FooFormatter {
    public String format() {
        return "foo";
    }
}

Then, we’ll inject this bean into the FooService bean using @Autowired on the field definition:

然后,我们将使用字段定义上的@Autowired将这个Bean注入到FooServiceBean。

@Component
public class FooService {  
    @Autowired
    private FooFormatter fooFormatter;
}

As a result, Spring injects fooFormatter when FooService is created.

因此,Spring在创建FooService时注入了fooFormatter

3.2. @Autowired on Setters

3.2.@Autowired on Setters

Now let’s try adding @Autowired annotation on a setter method.

现在让我们试着在一个setter方法上添加 @Autowired注解。

In the following example, the setter method is called with the instance of FooFormatter when FooService is created:

在下面的例子中,当FooFormatter被创建时,setter方法与FooService的实例被调用。

public class FooService {
    private FooFormatter fooFormatter;
    @Autowired
    public void setFormatter(FooFormatter fooFormatter) {
        this.fooFormatter = fooFormatter;
    }
}

3.3. @Autowired on Constructors

3.3.@Autowired on Constructors

Finally, let’s use @Autowired on a constructor.

最后,让我们在构造函数上使用@Autowired

We’ll see that an instance of FooFormatter is injected by Spring as an argument to the FooService constructor:

我们将看到一个FooFormatter的实例被Spring注入,作为FooService构造函数的一个参数。

public class FooService {
    private FooFormatter fooFormatter;
    @Autowired
    public FooService(FooFormatter fooFormatter) {
        this.fooFormatter = fooFormatter;
    }
}

4. @Autowired and Optional Dependencies

4.@Autowired和可选的依赖性

When a bean is being constructed, the @Autowired dependencies should be available. Otherwise, if Spring cannot resolve a bean for wiring, it will throw an exception.

在构造Bean时,@Autowired依赖关系应该是可用的。否则,如果Spring无法解决Bean的布线问题,它将抛出一个异常

Consequently, it prevents the Spring container from launching successfully with an exception of the form:

因此,它阻止了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)}

To fix this, we need to declare a bean of the required type:

为了解决这个问题,我们需要声明一个所需类型的bean。

public class FooService {
    @Autowired(required = false)
    private FooDAO dataAccessor; 
}

5. Autowire Disambiguation

5.自动线的歧义

By default, Spring resolves @Autowired entries by type. If more than one bean of the same type is available in the container, the framework will throw a fatal exception.

默认情况下,Spring按类型解析@Autowired条目。如果容器中存在多个相同类型的Bean,框架将抛出一个致命的异常

To resolve this conflict, we need to tell Spring explicitly which bean we want to inject.

为了解决这个冲突,我们需要明确地告诉Spring我们要注入哪个bean。

5.1. Autowiring by @Qualifier

5.1.通过@Qualifier自动布线。

For instance, let’s see how we can use the @Qualifier annotation to indicate the required bean.

例如,让我们看看如何使用@Qualifier注解来表示所需的bean。

First, we’ll define 2 beans of type Formatter:

首先,我们将定义2个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";
    }
}

Now let’s try to inject a Formatter bean into the FooService class:

现在让我们尝试将一个Formatterbean注入到FooService类。

public class FooService {
    @Autowired
    private Formatter formatter;
}

In our example, there are two concrete implementations of Formatter available for the Spring container. As a result, Spring will throw a NoUniqueBeanDefinitionException exception when constructing the FooService:

在我们的例子中,Spring容器有两个Formatter的具体实现。因此,Spring在构造FooService时将抛出一个NoUniqueBeanDefinitionException异常:

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

We can avoid this by narrowing the implementation using a @Qualifier annotation:

我们可以通过使用@Qualifier注解缩小实现范围来避免这种情况:

public class FooService {
    @Autowired
    @Qualifier("fooFormatter")
    private Formatter formatter;
}

When there are multiple beans of the same type, it’s a good idea to use @Qualifier to avoid ambiguity.

当有多个相同类型的豆子时,使用@Qualifier来避免歧义是一个好主意。

Please note that the value of the @Qualifier annotation matches with the name declared in the @Component annotation of our FooFormatter implementation.

请注意,@Qualifier注解的值与我们的@Component注解的FooFormatter实现中声明的名称相匹配。

5.2. Autowiring by Custom Qualifier

5.2.通过自定义限定符进行自动布线

Spring also allows us to create our own custom @Qualifier annotation. To do so, we should provide the @Qualifier annotation with the definition:

Spring还允许我们创建我们自己的自定义@Qualifier注解。要做到这一点,我们应该在定义中提供@Qualifier注解。

@Qualifier
@Target({
  ElementType.FIELD, ElementType.METHOD, ElementType.TYPE, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
public @interface FormatterType {  
    String value();
}

Then we can use the FormatterType within various implementations to specify a custom 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";
    }
}

Finally, our custom Qualifier annotation is ready to use for autowiring:

最后,我们的自定义Qualifier注解已经准备好用于自动布线。

@Component
public class FooService {  
    @Autowired
    @FormatterType("Foo")
    private Formatter formatter;
}

The value specified in the @Target meta-annotation restricts where to apply the qualifier, which in our example is fields, methods, types, and parameters.

@Target元注释中指定的值限制了应用限定符的位置,在我们的例子中是字段、方法、类型和参数。

5.3. Autowiring by Name

5.3.按名称自动接线

Spring uses the bean’s name as a default qualifier value. It will inspect the container and look for a bean with the exact name as the property to autowire it.

Spring使用Bean的名字作为默认的限定值。它将检查容器并寻找一个与属性名称完全相同的Bean来自动连接它。

Hence, in our example, Spring matches the fooFormatter property name to the FooFormatter implementation. Therefore, it injects that specific implementation when constructing FooService:

因此,在我们的例子中,Spring将fooFormatter属性名与FooFormatter实现匹配。因此,它在构造FooService时注入了那个特定的实现。

public class FooService {
 @Autowired 
private Formatter fooFormatter; 
}

6. Conclusion

6.结论

In this article, we discussed autowiring and the different ways to use it. We also examined ways to solve two common autowiring exceptions caused by either a missing bean or an ambiguous bean injection.

在这篇文章中,我们讨论了自动布线和使用它的不同方法。我们还研究了解决两种常见的自动布线异常的方法,这两种异常是由缺失的Bean或不明确的Bean注入引起的。

The source code of this article is available on the GitHub project.

本文的源代码可在GitHub项目上获得。