338

我正在阅读 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(); 
    } 
}

将调用哪种设计方法?如何确保调用 Red 类的设计方法而不是 Blue?

4

3 回答 3

577

TL;博士

注释使@Autowired您无需在 XML 文件中自己进行接线(或任何其他方式),只需为您找到需要在哪里注入的内容并为您执行此操作。

完整解释

注释允许您跳过其他地方的@Autowired注入配置,并为您完成它。假设你的包是com.mycompany.movies你必须把这个标签放在你的 XML(应用程序上下文文件)中:

<context:component-scan base-package="com.mycompany.movies" />

此标签将执行自动扫描。假设每个必须成为 bean 的类都使用正确的注解进行注解,例如@Component(for simple bean) or @Controller(for a servlet control) or @Repository(for DAOclasses) 并且这些类位于 package 下的某个位置com.mycompany.movies,Spring 将找到所有这些并创建每人一颗豆子。这是在对类的 2 次扫描中完成的——第一次它只是搜索需要成为 bean 的类并映射它需要执行的注入,而在第二次扫描时它会注入 bean。当然,您可以在更传统的 XML 文件中或使用@Configuration类(或三者的任意组合)来定义您的 bean。

@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
}

或者,如果您更喜欢在 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 不为空,并在尝试启动应用程序时快速失败,并避免NullPointerException在需要实际使用 bean 时。

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

于 2013-10-17T06:01:39.930 回答
21

示例中没有说明“实现相同接口的类”。MovieCatalog是一种类型,又CustomerPreferenceDao是另一种类型。春天可以很容易地把它们区分开来。

在 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 ) { ... }
于 2013-10-17T08:49:24.637 回答
5

是的,您可以配置 Spring servlet 上下文 xml 文件来定义您的 bean(即类),以便它可以为您进行自动注入。但是,请注意,您必须进行其他配置才能启动并运行 Spring,而最好的方法是按照教程进行操作。

配置好 Spring 后,您可以在 Spring servlet 上下文 xml 文件中执行以下操作,以使上面的示例 1 起作用(请将com.movi​​es的包名称替换为真正的包名称,如果这是第 3 方类,然后确保适当的 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。

于 2013-10-17T00:29:00.357 回答