我正在阅读spring 3.0.x参考文档,以了解Spring Autowired注释:
我无法理解以下示例。我们是否需要在XML中执行某些操作才能使用它?
示例1
public class SimpleMovieLister {
private MovieFinder movieFinder;
@Autowired
public void setMovieFinder(MovieFinder movieFinder) {
this.movieFinder = movieFinder;
}
// ...
}
示例2
public class MovieRecommender {
private MovieCatalog movieCatalog;
private CustomerPreferenceDao customerPreferenceDao;
@Autowired
public void prepare(MovieCatalog movieCatalog,
CustomerPreferenceDao customerPreferenceDao) {
this.movieCatalog = movieCatalog;
this.customerPreferenceDao = customerPreferenceDao;
}
// ...
}
这两个类如何通过自动装配实现相同的接口并使用相同的类?
示例:
class Red implements Color
class Blue implements Color
class myMainClass{
@Autowired
private Color color;
draw(){
color.design();
}
}
将调用哪种设计方法?如何确保调用Red类的设计方法而不是Blue?
答案 0 :(得分:506)
<强> TL; DR 强>
@Autowired注释让您无需在XML文件(或任何其他方式)中自行进行连接,只需找到需要注入的内容,并为您做到这一点。
完整解释
@Autowired
注释允许您跳过其他注入内容的配置,并为您执行此操作。假设您的包是com.mycompany.movies
,您必须将此标记放在XML(应用程序上下文文件)中:
<context:component-scan base-package="com.mycompany.movies" />
此标记将执行自动扫描。假设每个必须成为bean的类都使用正确的注释进行注释,例如@Component
(对于简单bean)或@Controller
(对于servlet控件)或@Repository
(对于DAO
这些类在包com.mycompany.movies
下的某个地方,Spring会找到所有这些并为每个创建一个bean。这是在对类的2次扫描中完成的 - 第一次只搜索需要成为bean的类并映射它需要进行的注入,并在第二次扫描时注入bean。当然,您可以在更传统的XML文件中定义bean,或者使用@Configuration类(或三者的任意组合)来定义bean。
@Autowired
注释告诉Spring需要注入的位置。如果将它放在方法setMovieFinder
上,它(通过前缀set
+ @Autowired
注释)理解需要注入bean。在第二次扫描中,Spring搜索类型为MovieFinder
的bean,如果找到这样的bean,则会将其注入此方法。如果它找到两个这样的bean,你将获得Exception
。要避免Exception
,您可以使用@Qualifier
注释,并按以下方式告诉它注入两个bean中的哪一个:
@Qualifier("redBean")
class Red implements Color {
// Class code here
}
@Qualifier("blueBean")
class Blue implements Color {
// Class code here
}
或者如果您更喜欢在XML中声明bean,它看起来像这样:
<bean id="redBean" class="com.mycompany.movies.Red"/>
<bean id="blueBean" class="com.mycompany.movies.Blue"/>
在@Autowired
声明中,您还需要添加@Qualifier
以告知要注入的两个颜色bean中的哪一个:
@Autowired
@Qualifier("redBean")
public void setColor(Color color) {
this.color = color;
}
如果您不想使用两个注释(@Autowired
和@Qualifier
),可以使用@Resource
将这两个注释结合起来:
@Resource(name="redBean")
public void setColor(Color color) {
this.color = color;
}
@Resource
(你可以在关于这个答案的第一条评论中阅读一些关于它的额外数据)使你无法使用两个注释,而只使用一个注释。
我将再添加两条评论:
@Inject
代替@Autowired
,因为它不是特定于Spring的,而是part of the JSR-330
standard。 @Inject
/ @Autowired
放在构造函数而不是方法上。如果将它放在构造函数上,则可以验证注入的bean不是null并且在尝试启动应用程序时快速失败并在需要实际使用bean时避免使用NullPointerException
。 更新:为了完成图片,我创建了一个关于@Configuration
课程的new question。
答案 1 :(得分:17)
示例中没有任何内容表示“实现相同接口的类”。 MovieCatalog
是一种类型,CustomerPreferenceDao
是另一种类型。 Spring很容易将它们分开。
在Spring 2.x中,bean的连线主要通过bean ID或名称进行。 Spring 3.x仍然支持这一点,但通常,您将拥有一个具有特定类型的bean实例 - 大多数服务都是单例。为这些创建名称是乏味的。所以Spring开始支持“按类型自动装配”。
示例显示了可用于将bean注入字段,方法和构造函数的各种方法。
XML已经包含Spring需要的所有信息,因为您必须在每个bean中指定完全限定的类名。但是你需要对接口有点小心:
此自动装配将失败:
@Autowired
public void prepare( Interface1 bean1, Interface1 bean2 ) { ... }
由于Java没有在字节代码中保留参数名称,因此Spring无法再区分这两个bean。修复方法是使用@Qualifier
:
@Autowired
public void prepare( @Qualifier("bean1") Interface1 bean1,
@Qualifier("bean2") Interface1 bean2 ) { ... }
答案 2 :(得分:5)
是的,您可以配置Spring servlet context xml文件来定义您的bean(即类),以便它可以为您执行自动注入。但是,请注意,您必须执行其他配置才能启动并运行Spring,最好的方法是按照教程进行操作。
一旦你的Spring配置完毕,你可以在上面的例1的Spring servlet上下文xml文件中执行以下操作(请替换 com.movies <的包名称/ strong>到真正的包名是什么,如果这是第三方类,那么请确保相应的jar文件在类路径上):
<beans:bean id="movieFinder" class="com.movies.MovieFinder" />
或者如果MovieFinder类有一个具有原始值的构造函数,那么你可以这样,
<beans:bean id="movieFinder" class="com.movies.MovieFinder" >
<beans:constructor-arg value="100" />
</beans:bean>
或者如果MovieFinder类有一个期望另一个类的构造函数,那么你可以做这样的事情,
<beans:bean id="movieFinder" class="com.movies.MovieFinder" >
<beans:constructor-arg ref="otherBeanRef" />
</beans:bean>
...其中' otherBeanRef '是另一个引用了期望类的bean。