2.2.4 通过为 bean 添加注解实现自动装配

简单来说,自动装配就是让 Spring 自动满足 bean 依赖的一种方法,在满足依赖的过程中,会在 Spring 应用上下文中寻找匹配某个 bean 需求的其他 bean。为了声明要进行自动装配,我们可以借助 Spring 的 @Autowired 注解。

比方说,考虑以下代码中的 CDPlayer 类:

CDPlayer.java
package soundsystem;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class CDPlayer implements MediaPlayer {
  private CompactDisc cd;

  @Autowired
  public CDPlayer(CompactDisc cd) {
    this.cd = cd;
  }

  public void play() {
    cd.play();
  }

}

它的构造器上添加了 @Autowired 注解,这表明当 Spring 创建 CDPlayerbean 的时候,会通过这个构造器来进行实例化并且会传入一个可设置给 CompactDisc 类型的 bean,将一个 CompactDisc 注入到 CDPlayer 之中。

@Autowired 注解不仅能够用在构造器上,还能用在属性的 Setter 方法上。比如说,如果 CDPlayer 有一个 setCompactDisc() 方法,那 么可以采用如下的注解形式进行自动装配:

CDPlayer.java
@Autowired
public void setCompactDisc(CompactDisc cd){
  this.cd = cd;
}

在 Spring 初始化 bean 之后,它会尽可能得去满足 bean 的依赖,在本例中,依赖是通过带有 @Autowired 注解的方法进行声明的,也就是 setCompactDisc()。

实际上,Setter 方法并没有什么特殊之处。@Autowired 注解可以用在类的任何方法上。假设 CDPlayer 类有一个 insertDisc() 方法, 那么 @Autowired 能够像在 setCompactDisc() 上那样,发挥完全相同的作用:

CDPlayer.java
@Autowired
public void insertDisc(CompactDisc cd){
  this.cd = cd;
}

不管是构造器、Setter 方法还是其他的方法,Spring 都会尝试满足方法参数上所声明的依赖。假如有且只有一个 bean 匹配依赖需求的话,那 么这个 bean 将会被装配进来。如果没有匹配的 bean,那么在应用上下文创建的时候,Spring 会抛出 一个异常。为了避免异常的出现,你可以将 @Autowired 的 required 属性设置为 false:

CDPlayer.java
@Autowired(required=false)
public CDPlayer(CompactDisc cd) {
  this.cd = cd;
}

将 required 属性设置为false 时,Spring 会尝试执行自动装配,但是如果没有匹配的 bean 的话,Spring 将会让这个 bean 处于未装配的状 态。但是,把 required 属性设置为 false 时,你需要谨慎对待。如果在你的代码中没有进行 null 检查的话,这个处于未装配状态的属性有可能会出现 NullPointerException。

如果有多个 bean 都能满足依赖关系的话,Spring 将会抛出一个异常,表明没有明确指定要选择哪个 bean 进行自动装配。在第 3 章中,我们会进一步讨论自动装配中的歧义性。

@Autowired 是 Spring 特有的注解。如果你不愿意在代码中到处使用 Spring 的特定注解来完成自动装配任务的话,那么你可以考虑将其替换为 @Inject:

package soundsystem;
import javax.inject.Inject;
import javax.inject.Named;

@Named
public class CDPlayer {
  ...

  @Inject
  public CDPlayer(CompactDisc cd) {
    this.cd = cd;
  }
  
  ...
}

@Inject 注解来源于Java 依赖注入规范,该规范同时还为我们定义了 @Named 注解。在自动装配中,Spring 同时支持 @Inject 和 @Autowired。尽管 @Inject 和 @Autowired 之间有着一些细微的差别,但是在大多数场景下,它们都是可以互相替换的。

在 @Inject 和 @Autowired 中,我没有特别强烈的偏向性。实际上,在有的项目中,我会发现我同时使用了这两个注解。不过在本书的样例中,我会一直使用 @Autowired,而你可以根据自己的情况,选择其中的任意一个。

Last updated