理解Spring @Autowired的用法

我在读spring 3.0。x参考文档来理解Spring Autowired注释:

3.9.2 @Autowired和@Inject

我不能理解下面的例子。我们需要在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();
}
}

将调用哪个设计方法?我如何确保红色类的设计方法将被调用,而不是蓝色?

458857 次浏览

是的,您可以配置Spring servlet上下文xml文件来定义bean(即类),这样它就可以为您自动注入。但是,请注意,要启动并运行Spring,您必须进行其他配置,做到这一点的最佳方法是从头开始学习教程。

一旦你配置了你的Spring,你可以在你的Spring servlet上下文xml文件中做以下工作,上面的例子1(请取代 com.movies的包名是真正的包名,如果这是一个第三方类,那么确保适当的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,它具有对期望类的引用。

博士TL;

@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。这在类的两次扫描中完成——第一次它只是搜索需要成为bean的类并映射它需要执行的注入,而在第二次扫描中它注入bean。当然,您可以在更传统的XML文件或@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(你可以在这个答案的第一个注释中读到一些关于它的额外数据)使你不用使用两个注释,相反,你只使用一个注释。

我再加两点评论:

  1. 好的做法是使用@Inject而不是@Autowired,因为它不是spring特定的,并且是JSR-330标准的一部分
  2. 另一个好的实践是将@Inject / @Autowired放在构造函数上而不是方法上。如果你把它放在构造函数上,你可以验证注入的bean不是空的,并且在你试图启动应用程序时快速失败,并在你需要实际使用bean时避免NullPointerException

更新:为了完成这个图,我创建了一个关于@Configuration类的新问题

这个例子中没有说“类实现了相同的接口”。MovieCatalog是一种类型,CustomerPreferenceDao是另一种类型。春天很容易就能把它们区分开来。

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 ) { ... }