我正在阅读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?

#1 楼

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文件中或使用@Configuration类(或这三个的任意组合)定义bean。
@Autowired批注告诉Spring需要在哪里进行注入。如果将其放在方法setMovieFinder上,它将理解(通过前缀set + @Autowired注释)需要注入一个bean。在第二次扫描中,Spring搜索类型为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来指示要注入的两种颜色的豆:
@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的,而是JSR-330标准的一部分。
另一个好的做法是将@Inject / @Autowired放在构造函数上,而不是方法上。如果将其放在构造函数上,则可以验证注入的bean不是null并在尝试启动应用程序时快速失败,并在需要实际使用bean时避免使用NullPointerException

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

评论


只是为了完成您的出色回答:“ @ Resource”是JSR-250标准的一部分,除简单注入外,还具有其他语义(如您所说的“ @Autowired”来自Spring;而“ @Inject”则是JSR-330):)

–伊格纳西奥·卢比奥(Ignacio Rubio)
2014年9月1日15:12

如果MovieFinder是一个接口,并且我们有一个用于MovieFinderImpl的bean(bean id = movieFinder),Spring将按类型或名称自动注入它吗?

–Jaskey
15年8月8日在12:37

@jaskey-这取决于您是否使用@Qualifier。如果您这样做-按名称,如果不是,则按类型。仅当您的上下文中只有一个MovieFinder类型的bean时,“按类型”才有效。大于1会导致异常。

–阿维
15年8月8日在17:07

@Avi,很棒的答案。但是我不明白@Autowired注释如何在示例2中的prepare方法上工作。它正在初始化MovieRecommender,但从技术上讲,它不是设置方法。

– Karan Chadha
17-2-28在9:26



@KaranChadha-@Autowired也适用于构造函数。它找到所需的依赖项并将其注入到构造函数中。

–阿维
17年2月28日在9:59

#2 楼

该示例中没有任何内容说“实现相同接口的类”。 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 ) { ... }


评论


@AaronDigulla很好。但是我想知道您如何调用函数prepare,将使用哪些参数来调用此函数?

–阮光安(Nguyen Quang Anh)
17年7月10日在2:04

@NguyenQuangAnh我没有调用该方法,在创建bean时Spring会这样做。恰好在注入@Autowired字段时发生。然后,Spring将看到需要参数,并且它将使用与字段注入相同的规则来查找参数。

–亚伦·迪古拉(Aaron Digulla)
17年9月4日在11:53

#3 楼

是的,您可以配置Spring servlet上下文xml文件来定义您的bean(即类),以便它可以为您进行自动注入。但是,请注意,要使Spring正常运行,您必须进行其他配置,而最好的方法是遵循本教程。

一旦配置好Spring,您可以在上面的示例1的Spring servlet上下文xml文件中执行以下操作以工作(请将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。

评论


在XML中定义所有连接只是错过了@Autowired的整个想法

–阿维
13-10-17在6:51