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类型的Bean。
@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.
当有多个相同类型的Bean时,使用@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项目上获得。