了解弹簧@Autowired用法

2022-08-31 04:52:56

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

注释使您无需在XML文件中自己进行连接(或任何其他方式),只需为您找到需要注入的内容并为您完成。@Autowired

完整解释

注释允许您跳过其他地方的配置,并为您完成。假设您的软件包必须将此标记放在 XML(应用程序上下文文件)中:@Autowiredcom.mycompany.movies

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

此标记将执行自动扫描。假设每个必须成为bean的类都用正确的注释进行注释,例如(对于简单的bean)或(对于servlet控件)或(对于类),并且这些类位于包下的某个位置,Spring将找到所有这些并为每个类创建一个bean。这是在2次扫描类中完成的 - 第一次它只是搜索需要成为bean的类并映射它需要做的注入,而在第二次扫描中,它注入bean。当然,您可以在更传统的 XML 文件中或使用@Configuration类(或三者的任意组合)定义 Bean。@Component@Controller@RepositoryDAOcom.mycompany.movies

注释告诉Spring需要在哪里进行注射。如果你把它放在一个方法上,它理解(通过前缀+注释)需要注入一个bean。在第二次扫描中,Spring搜索类型的豆子,如果找到这样的豆子,则将其注入此方法。如果它找到两个这样的豆子,你会得到一个.要避免 ,您可以使用注释并按以下方式告诉它要注入两个 Bean 中的哪一个:@AutowiredsetMovieFinderset@AutowiredMovieFinderExceptionException@Qualifier

@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

我只想再添加两条评论:

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

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


答案 2

示例中没有任何内容表明“实现相同接口的类”。 是一种类型,是另一种类型。春天可以很容易地将它们区分开来。MovieCatalogCustomerPreferenceDao

在Spring 2.x中,豆的连接主要通过豆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 ) { ... }

推荐