装配

创建应用对象之间协作关系的行为通常称为装配(wiring),这也是依赖注入(DI)的本质。

Spring 容器负责创建应用程序中的 bean 并通过 DI 来协调这些对象之间的关系。但是,作为开发人员,我们需要告诉 Spring 要创建哪些 bean 并且如何将其装配在一起。

Spring 提供了三种主要的装配机制:

  • 在 XML 中进行显式配置。

  • 在 Java 中进行显式配置。

  • 隐式的 bean 发现机制和自动装配。

Spring 的配置风格是可以互相搭配的,所以可以选择使用 XML 装配一些 bean,使用 Spring 基于 Java 的配置(JavaConfig)来装配另一些 bean,而将剩余的 bean 让 Spring 去自动发现。

  1. 建议尽可能地使用自动配置的机制,显式配置越少越好

  2. 当你必须要显式配置 bean 的时候(比如,有些源码不是由你来维护的,而你需要为这些代码配置 bean),推荐使用类型安全并且比 XML 更加强大的 JavaConfig。

  3. 只有当你想要使用便利的 XML 命名空间,并且在 JavaConfig 中没有同样的实现时,才应该使用 XML。

自动装配

Spring 从两个角度来实现自动化装配:

  • 组件扫描(component scanning):Spring 会自动发现应用上下文中所创建的 bean。

  • 自动装配(autowiring):Spring 自动满足 bean 之间的依赖。

相关的 3 个主要注解为:

  • @ComponentScan

    @ComponentScan 注解启用了组件扫描。

    如果没有其他配置的话,@ComponentScan 默认会扫描与注解所标注的类相同的包,以及这个包下的所有子包,查找带有 @Component 注解的类。

  • @Component

    这个简单的注解表明该类会作为组件类,并告知 Spring 要为这个类创建 bean。

    Spring 应用上下文中所有的 bean 都会给定一个 ID。默认情况下,Spring 会根据类名为其指定一个 ID,如果想为这个 bean 设置不同的 ID,你所要做的就是将期望的 ID 作为值传递给 @Component 注解。

  • @Autowired

    为了声明要进行自动装配,我们可以借助 Spring 的 @Autowired 注解。

    @Autowired 注解不仅能够用在构造器上,还能用在属性的 Setter 方法上。

在 Java 中进行显式配置

创建 JavaConfig 类的关键在于为其添加 @Configuration 注解,@Configuration 注解表明这个类是一个配置类,该类应该包含在 Spring 应用上下文中如何创建 bean 的细节。

1. 声明 bean

要在 JavaConfig 中声明 bean,我们需要编写一个方法,这个方法会创建所需类型的实例,然后给这个方法添加 @Bean 注解。@Bean 注解会告诉 Spring 这个方法将会返回一个对象,该对象要注册为 Spring 应用上下文中的 bean。方法体中包含了最终产生 bean 实例的逻辑。

默认情况下,bean 的 ID 与带有 @Bean 注解的方法名是一样的。如果你想为其设置成一个不同的名字的话,那么可以重命名该方法,也可以通过 name 属性指定一个不同的名字。

2. 注入

在 JavaConfig 中装配 bean 的最简单方式就是引用创建 bean 的方法

@Bean
public CDPlayer cdPlayer() {
  return new CDPlayer(sgtPeppers());
}

@Bean
public CDPlayer anotherCDPlayer() {
  return new CDPlayer(sgtPeppers());
}

默认情况下,Spring 中的 bean 都是单例的,我们没有必要为第二个 CDPlayer bean 创建完全相同的 SgtPeppers 实例。所以,Spring 会拦截对 sgtPeppers() 的调用并确保返回的是 Spring 所创建的 bean,也就是 Spring 本身在调用 sgtPeppers() 时所创建的 CompactDisc bean。因此,在上面的程序片段中,两个 CDPlayer bean 会得到相同的 SgtPeppers 实例

还有一种理解起来更为简单的方式:

@Bean
public CDPlayer cdPlayer(CompactDisc compactDisc) {
  return new CDPlayer(compactDisc);
}

在这里,cdPlayer() 方法请求一个 CompactDisc 作为参数。当 Spring 调用 cdPlayer() 创建 CDPlayer bean 的时候,它会自动装配一个 CompactDisc 到配置方法之中。然后,方法体就可以按照合适的方式来使用它。借助这种技术,cdPlayer() 方法也能够将 CompactDisc 注入到 CDPlayer 的构造器中,而且不用明确引用 CompactDisc 的 @Bean 方法。

通过这种方式引用其他的 bean 通常是最佳的选择,因为它不会要求将 CompactDisc 声明到同一个配置类之中。在这里甚至没有要求 CompactDisc 必须要在 JavaConfig 中声明,实际上它可以通过组件扫描功能自动发现或者通过 XML 来进行配置。你可以将配置分散到多个配置类、XML 文件以及自动扫描和装配 bean 之中,只要功能完整健全即可。不管 CompactDisc 是采用什么方式创建出来的,Spring 都会将其传入到配置方法中,并用来创建 CDPlayer bean。

混合配置

关于混合配置,第一件需要了解的事情就是在自动装配时,它并不在意要装配的 bean 来自哪里。自动装配的时候会考虑到 Spring 容器中所有的 bean,不管它是在 JavaConfig 或 XML 中声明的还是通过组件扫描获取到的。

Last updated