注解自动化是一种隐式装配方式,当自动化装配方案行不通的时候,可以考虑通过JavaConfig方案实现,虽然它也是Java代码,但是它仅仅是配置代码,不包含业务逻辑,也不会涉及到业务逻辑当中,有时候JavaConfig可以单独放到一个包里,与其它应用程序逻辑分离

创建JavaConfig类主要还是为了添加@Configuration注解,这个注解表明这是一个配置类,该类应该包含了在Spring应用上下文中如何创建bean的细节;之前都是通过扫描来发现Spring应该创建的bean,这里显示配置就将@ComponentScan扫描注解去掉

也就是与自动化配置相比,大部分去掉一些注解,比如去掉了注解装配方式中的@ComponentScan注解,缺少了扫描功能,CDPlayerConfig类就没有任何作用,因为测试期望被注入CDPlayer和CompactDisc,但是这些bean根本就没创建,因为组件扫描无法发现

首先是MediaPlayer

packagecom.maoxiaomeng.javaconfig;/*** Copyright (C), 2014-2018, maoxiaomeng.com* FileName: MediaPlayer* Author: lihui* Date: 2018/6/22 下午11:08*/public interfaceMediaPlayer {
voidplay();}
接着是CDPlayer,去掉自动化配置注解在类CDPlayer的@Component
packagecom.maoxiaomeng.javaconfig;importorg.springframework.beans.factory.annotation.Autowired;/*** Copyright (C), 2014-2018, maoxiaomeng.com* FileName: CDPlayer* Author: lihui* Date: 2018/6/22 下午11:07*/public classCDPlayer implementsMediaPlayer {
privateCompactDisc cd; @Autowired publicCDPlayer(CompactDisc cd) {
this.cd= cd; }
public voidplay() {
cd.play(); }
}

CompactDisc接口

packagecom.maoxiaomeng.javaconfig;/*** Copyright (C), 2014-2018, maoxiaomeng.com* FileName: CompactDisc* Author: lihui* Date: 2018/6/22 下午11:09*/public interfaceCompactDisc {
voidplay();}
同样Yesterday去掉@Component
packagecom.maoxiaomeng.javaconfig;/*** Copyright (C), 2014-2018, maoxiaomeng.com* FileName: Yesterday* Author: lihui* Date: 2018/6/22 下午11:10*/public classYesterday implementsCompactDisc {
privateString title= "Yesterday Once More";privateString artist= "Carpenters";public voidplay() {
System.out.println("Playing "+ title+ " by "+ artist); }
}

之前注解装配方式里CDPlayerConfig只是通过注解来扫描组件,这里通过JavaConfig方式,显式装配CDPlayer和CompactDisc

正常通过JavaConfig装配bean最简单的方法是引用创建bean的方法,比如:

@BeanpublicCDPlayer cdPlayer(CompactDisc yesterday) {

return newCDPlayer(yesterday);}

这里使用@Bean注解,表明这个方法会创建一个bean实例,并将其注册到Spring应用上下文 中

CDPlayer()方法请求一个CompactDisc座位参数,当Spring调用CDPlayer()创建CDPlayer bean的时候,会自动装配一个CompactDisc到配置方法中,然后方法体可以按照合适的方法来使用它,这样CDPlayer()方法可以将CompactDisc注入到CDPlayer的构造函数中,而且不用明确引用CompactDisc的@Bean方法

packagecom.maoxiaomeng.javaconfig;importorg.springframework.context.annotation.Bean;importorg.springframework.context.annotation.Configuration;/*** Copyright (C), 2014-2018, maoxiaomeng.com* FileName: CDPlayerConfig* Author: lihui* Date: 2018/6/22 下午11:09*/@Configurationpublic classCDPlayerConfig {
@Bean publicCompactDisc yesterday() {
return newYesterday(); }
@Bean publicCDPlayer cdPlayer(CompactDisc yesterday) {
return newCDPlayer(yesterday); }
}

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

最后是测试类

packagecom.maoxiaomeng.javaconfig;importjunit.framework.TestCase;importorg.junit.Rule;importorg.junit.Test;importorg.junit.contrib.java.lang.system.StandardOutputStreamLog;importorg.junit.runner.RunWith;importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.test.context.ContextConfiguration;importorg.springframework.test.context.junit4.SpringJUnit4ClassRunner;/*** Copyright (C), 2014-2018, maoxiaomeng.com* FileName: CDPlayerTest* Author: lihui* Date: 2018/6/22 下午11:14*/@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes=CDPlayerConfig.class)
public classCDPlayerTest extendsTestCase {
@Rule public finalStandardOutputStreamLog log= newStandardOutputStreamLog(); @Autowired privateMediaPlayer player; @Test public voidplay() {
player.play(); assertEquals(
"Playing Yesterday Once More by Carpenters\n", log.getLog()); }
}

带有@Bean注解的方法可以采用任何必要的Java功能来产生bean实例