Java 了解 Spring @Autowired 的用法
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/19414734/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Understanding Spring @Autowired usage
提问by NewQueries
I am reading the spring 3.0.x reference documentation to understand Spring Autowired annotation:
我正在阅读 spring 3.0.x 参考文档以了解 Spring Autowired 注释:
I am not able to understand the below examples. Do we need to do something in the XML for it to work?
我无法理解以下示例。我们需要在 XML 中做些什么才能让它工作吗?
EXAMPLE 1
例 1
public class SimpleMovieLister {
private MovieFinder movieFinder;
@Autowired
public void setMovieFinder(MovieFinder movieFinder) {
this.movieFinder = movieFinder;
}
// ...
}
EXAMPLE 2
例2
public class MovieRecommender {
private MovieCatalog movieCatalog;
private CustomerPreferenceDao customerPreferenceDao;
@Autowired
public void prepare(MovieCatalog movieCatalog,
CustomerPreferenceDao customerPreferenceDao) {
this.movieCatalog = movieCatalog;
this.customerPreferenceDao = customerPreferenceDao;
}
// ...
}
How can the two classes be autowired implementing the same interface and using the same class?
如何自动装配这两个类,实现相同的接口并使用相同的类?
Example:
例子:
class Red implements Color
class Blue implements Color
class myMainClass{
@Autowired
private Color color;
draw(){
color.design();
}
}
Which design method will be called? How do I make sure the design method of Red class will be called and not Blue?
将调用哪种设计方法?如何确保将调用 Red 类的设计方法而不是 Blue?
采纳答案by Avi
TL;DR
TL; 博士
The @Autowired annotation spares you the need to do the wiring by yourself in the XML file (or any other way) and just finds for you what needs to be injected where, and does that for you.
@Autowired 注释使您无需在 XML 文件(或任何其他方式)中自己进行接线,只需为您找到需要注入到何处的内容,并为您执行此操作。
Full explanation
完整说明
The @Autowired
annotation allows you to skip configurations elsewhere of what to inject and just does it for you. Assuming your package is com.mycompany.movies
you have to put this tag in your XML (application context file):
该@Autowired
注释允许你对什么注入其他地方跳过配置,只是它给你的。假设你的包是com.mycompany.movies
你必须把这个标签放在你的 XML(应用程序上下文文件)中:
<context:component-scan base-package="com.mycompany.movies" />
This tag will do an auto-scanning. Assuming each class that has to become a bean is annotated with a correct annotation like @Component
(for simple bean) or @Controller
(for a servlet control) or @Repository
(for DAO
classes) and these classes are somewhere under the package com.mycompany.movies
, Spring will find all of these and create a bean for each one. This is done in 2 scans of the classes - the first time it just searches for classes that need to become a bean and maps the injections it needs to be doing, and on the second scan it injects the beans. Of course, you can define your beans in the more traditional XML file or with a @Configurationclass (or any combination of the three).
此标签将进行自动扫描。假设必须成为 bean 的每个类都使用正确的注释进行注释,例如@Component
(对于简单 bean)或@Controller
(对于 servlet 控件)或@Repository
(对于DAO
类),并且这些类位于包下的某个位置com.mycompany.movies
,Spring 将找到所有这些并创建每人一个豆子。这是在对类的 2 次扫描中完成的 - 第一次它只搜索需要成为 bean 的类并映射它需要执行的注入,然后在第二次扫描时注入 bean。当然,您可以在更传统的 XML 文件中或使用@Configuration类(或三者的任意组合)定义 bean 。
The @Autowired
annotation tells Spring where an injection needs to occur. If you put it on a method setMovieFinder
it understands (by the prefix set
+ the @Autowired
annotation) that a bean needs to be injected. In the second scan, Spring searches for a bean of type MovieFinder
, and if it finds such bean, it injects it to this method. If it finds two such beans you will get an Exception
. To avoid the Exception
, you can use the @Qualifier
annotation and tell it which of the two beans to inject in the following manner:
该@Autowired
注解告诉Spring去哪里注射需要发生。如果你把它放在一个方法上,setMovieFinder
它就知道(通过前缀set
+@Autowired
注释)需要注入一个 bean。在第二次扫描中,Spring 搜索类型为 的 bean MovieFinder
,如果找到这样的 bean,则将其注入到此方法中。如果它找到两个这样的 bean,你将得到一个Exception
. 为了避免Exception
,您可以使用@Qualifier
注释并通过以下方式告诉它要注入两个 bean 中的哪一个:
@Qualifier("redBean")
class Red implements Color {
// Class code here
}
@Qualifier("blueBean")
class Blue implements Color {
// Class code here
}
Or if you prefer to declare the beans in your XML, it would look something like this:
或者,如果您更喜欢在 XML 中声明 bean,它看起来像这样:
<bean id="redBean" class="com.mycompany.movies.Red"/>
<bean id="blueBean" class="com.mycompany.movies.Blue"/>
In the @Autowired
declaration, you need to also add the @Qualifier
to tell which of the two color beans to inject:
在@Autowired
声明中,您还需要添加@Qualifier
来告诉要注入两种颜色的bean中的哪一种:
@Autowired
@Qualifier("redBean")
public void setColor(Color color) {
this.color = color;
}
If you don't want to use two annotations (the @Autowired
and @Qualifier
) you can use @Resource
to combine these two:
如果您不想使用两个注释(@Autowired
和@Qualifier
),您可以@Resource
将这两个注释结合起来:
@Resource(name="redBean")
public void setColor(Color color) {
this.color = color;
}
The @Resource
(you can read some extra data about it in the first comment on this answer) spares you the use of two annotations and instead you only use one.
在@Resource
(你可以在这个答案的第一个评论阅读关于它的一些额外的数据),备件您使用两个注释,而是只使用一个。
I'll just add two more comments:
我再补充两条评论:
- Good practice would be to use
@Inject
instead of@Autowired
because it is not Spring-specific and is part of theJSR-330
standard. - Another good practice would be to put the
@Inject
/@Autowired
on a constructor instead of a method. If you put it on a constructor, you can validate that the injected beans are not null and fail fast when you try to start the application and avoid aNullPointerException
when you need to actually use the bean.
- 良好做法是使用
@Inject
替代的@Autowired
,因为它不是春,具体是将一部分JSR-330
标准。 - 另一个好的做法是将
@Inject
/@Autowired
放在构造函数而不是方法上。如果将它放在构造函数上,则可以验证注入的 bean 是否为空,并且在尝试启动应用程序时会快速失败,并NullPointerException
在需要实际使用 bean 时避免 a 。
Update: To complete the picture, I created a new questionabout the @Configuration
class.
更新:为了完成图片,我创建了一个关于班级的新问题@Configuration
。
回答by Cem Sultan
Yes, you can configure the Spring servlet context xml file to define your beans (i.e., classes), so that it can do the automatic injection for you. However, do note, that you have to do other configurations to have Spring up and running and the best way to do that, is to follow a tutorial ground up.
是的,您可以配置 Spring servlet 上下文 xml 文件来定义您的 bean(即类),以便它可以为您进行自动注入。但是,请注意,您必须进行其他配置才能启动和运行 Spring,而最好的方法是按照教程进行操作。
Once you have your Spring configured probably, you can do the following in your Spring servlet context xml file for Example 1 above to work (please replacethe package name of com.moviesto what the true package name is and if this is a 3rd party class, then be sure that the appropriate jar file is on the classpath) :
一旦您可能配置了 Spring,您可以在上面的示例 1 的 Spring servlet 上下文 xml 文件中执行以下操作(请将com.movies的包名替换为真正的包名,如果这是第 3 方类,然后确保相应的 jar 文件位于类路径中):
<beans:bean id="movieFinder" class="com.movies.MovieFinder" />
or if the MovieFinder class has a constructor with a primitive value, then you could something like this,
或者如果 MovieFinder 类有一个带有原始值的构造函数,那么你可以像这样,
<beans:bean id="movieFinder" class="com.movies.MovieFinder" >
<beans:constructor-arg value="100" />
</beans:bean>
or if the MovieFinder class has a constructor expecting another class, then you could do something like this,
或者如果 MovieFinder 类有一个需要另一个类的构造函数,那么你可以做这样的事情,
<beans:bean id="movieFinder" class="com.movies.MovieFinder" >
<beans:constructor-arg ref="otherBeanRef" />
</beans:bean>
...where 'otherBeanRef' is another bean that has a reference to the expected class.
...其中 ' otherBeanRef' 是另一个具有对预期类的引用的 bean。
回答by Aaron Digulla
Nothing in the example says that the "classes implementing the same interface". MovieCatalog
is a type and CustomerPreferenceDao
is another type. Spring can easily tell them apart.
示例中没有任何内容说“实现相同接口的类”。MovieCatalog
是一种类型并且CustomerPreferenceDao
是另一种类型。Spring 可以很容易地将它们区分开来。
In Spring 2.x, wiring of beans mostly happened via bean IDs or names. This is still supported by Spring 3.x but often, you will have one instance of a bean with a certain type - most services are singletons. Creating names for those is tedious. So Spring started to support "autowire by type".
在 Spring 2.x 中,bean 的连接主要通过 bean ID 或名称进行。Spring 3.x 仍然支持这一点,但通常情况下,您将拥有一个特定类型的 bean 实例——大多数服务都是单例的。为这些命名是乏味的。所以Spring开始支持“按类型自动装配”。
What the examples show is various ways that you can use to inject beans into fields, methods and constructors.
示例显示的是可用于将 bean 注入字段、方法和构造函数的各种方法。
The XML already contains all the information that Spring needs since you have to specify the fully qualified class name in each bean. You need to be a bit careful with interfaces, though:
XML 已经包含 Spring 需要的所有信息,因为您必须在每个 bean 中指定完全限定的类名。但是,您需要对接口小心一点:
This autowiring will fail:
此自动装配将失败:
@Autowired
public void prepare( Interface1 bean1, Interface1 bean2 ) { ... }
Since Java doesn't keep the parameter names in the byte code, Spring can't distinguish between the two beans anymore. The fix is to use @Qualifier
:
由于 Java 不会在字节码中保留参数名称,因此 Spring 无法再区分这两个 bean。解决方法是使用@Qualifier
:
@Autowired
public void prepare( @Qualifier("bean1") Interface1 bean1,
@Qualifier("bean2") Interface1 bean2 ) { ... }