2.3 通过 Java 代码装配 bean
Q:在什么情况下需要通过 Java 代码装配 bean?
A:有时候自动化配置的方案行不通,此时需要明确配置 Spring。比如说,你想要将第三方库中的组件装配到你的应用中,这种情况下,是没有办法在它的类上添加 @Component 和 @Autowired 注解的,因此就不能使用自动化配置的方案了。
Q:为什么说在进行显示配置时, JavaConfig 是更好的方案?
A:因为它更为强大、类型安全并且对重构友好。它就是 Java 代码,就像应用程序中的其他 Java 代码一样。
注意:JavaConfig 是配置代码,不应该包含任何业务逻辑代码,不应该侵入到业务逻辑代码之中。通常会将 JavaConfig 放到单独的包中,使它与其他的应用程序逻辑分离开来。
之前需要提前创建哪些具体的类,请参考前一篇:Spring 如何使用自动化装配 bean?
Q:如何通过 JavaConfig 显式配置 Spring?
A:①、创建配置类
CDPlayerConfig.java
package soundsystem;
import org.springframework.context.annotation.Configuration;
/**
* 创建 JavaConfig 类的关键在于为其添加 @Configuration 注解,
* @Configuration 注解表明这个类是一个配置类,该类应该包含在 Spring 应用上下文中如何创建 bean 的细节。
*/
@Configuration
public class CDPlayerConfig {
}
前一篇自动化装配的时候,我们都是依赖组件扫描来发现 Spring 应该创建的 bean。这里我们将进行显式配置。
②、声明简单的 bean
要在 JavaConfig 中声明 bean,首先编写一个方法,这个方法会创建所需类型的实例,然后给这个方法添加 @Bean 注解。
CDPlayerConfig.java
/**
* @Bean 注解会告诉 Spring 这个方法将会返回一个对象,该对象要注册为 Spring 应用上下文中的 bean。
* 默认情况下,bean 的 ID 与该方法名一样。或者通过 name 属性指定一个名字。
*/
//@Bean
@Bean(name = "lonelyHeartsClubBand")
public CompactDisc sgtPeppers(){
/*
* 此处包含最终产生 bean 实例的逻辑。可以自由发挥。比如随机生成一种实例。
*/
return new SgtPeppers();
}
③、借助 JavaConfig 实现注入
/**
* 在 JavaConfig 中装配 bean 的方式之一:引用创建 bean 的方法
*/
@Bean
public CDPlayer cdPlayer(){
/*
注意:此处看起来,CompactDisc 是通过调用 sgtPeppers() 方法得到的,但实际并非如此。
因为 sgtPeppers() 方法上添加了 @Bean 注解,Spring 就会拦截所有对它的调用,
并确保直接返回该方法所创建的 bean,也就是 Spring 本身在调用 sgtPeppers() 时创建的 CompactDiscbean。
所以 Spring 创建的 CompactDiscbean 是单例的,不管调用几次 sgtPeppers(),返回的永远的同一个 bean。
*/
return new CDPlayer(sgtPeppers());
}
/**
* 在 JavaConfig 中装配 bean 的方式之二:使用 CDPlayer 的构造器实现了 DI 功能
* 请求一个 CompactDisc 作为参数。(最佳选择!!!)
* 优点:不会要求将 CompactDisc 声明到同一个配置类之中。
*
* 当 Spring 调用该方法创建 CDPlayerbean 时,它会自动装配一个 CompactDisc 到配置方法之中。
* 借助这种技术,该方法也能够将 CompactDisc 注入到 CDPlayer的构造器中,而且不用明确引用 CompactDisc 的 @Bean 方法。
*/
@Bean
public CDPlayer cdPlayer(CompactDisc compactDisc){
return new CDPlayer(compactDisc);
}