注解自动化是一种隐式装配方式,当自动化装配方案行不通的时候,可以考虑通过JavaConfig方案实现,虽然它也是Java代码,但是它仅仅是配置代码,不包含业务逻辑,也不会涉及到业务逻辑当中,有时候JavaConfig可以单独放到一个包里,与其它应用程序逻辑分离
创建JavaConfig类主要还是为了添加@Configuration注解,这个注解表明这是一个配置类,该类应该包含了在Spring应用上下文中如何创建bean的细节;之前都是通过扫描来发现Spring应该创建的bean,这里显示配置就将@ComponentScan扫描注解去掉
也就是与自动化配置相比,大部分去掉一些注解,比如去掉了注解装配方式中的@ComponentScan注解,缺少了扫描功能,CDPlayerConfig类就没有任何作用,因为测试期望被注入CDPlayer和CompactDisc,但是这些bean根本就没创建,因为组件扫描无法发现
首先是MediaPlayer
package com.maoxiaomeng.javaconfig;
/**
* Copyright (C), 2014-2018, maoxiaomeng.com
* FileName: MediaPlayer
* Author: lihui
* Date: 2018/6/22 下午11:08
*/
public interface MediaPlayer {
void play();
}
接着是CDPlayer,去掉自动化配置注解在类CDPlayer的@Component
package com.maoxiaomeng.javaconfig;
import org.springframework.beans.factory.annotation.Autowired;
/**
* Copyright (C), 2014-2018, maoxiaomeng.com
* FileName: CDPlayer
* Author: lihui
* Date: 2018/6/22 下午11:07
*/
public class CDPlayer implements MediaPlayer {
private CompactDisc cd;
@Autowired
public CDPlayer(CompactDisc cd) {
this.cd = cd;
}
public void play() {
cd.play();
}
}
CompactDisc接口
package com.maoxiaomeng.javaconfig;
/**
* Copyright (C), 2014-2018, maoxiaomeng.com
* FileName: CompactDisc
* Author: lihui
* Date: 2018/6/22 下午11:09
*/
public interface CompactDisc {
void play();
}
同样Yesterday去掉@Component
package com.maoxiaomeng.javaconfig;
/**
* Copyright (C), 2014-2018, maoxiaomeng.com
* FileName: Yesterday
* Author: lihui
* Date: 2018/6/22 下午11:10
*/
public class Yesterday implements CompactDisc {
private String title = "Yesterday Once More";
private String artist = "Carpenters";
public void play() {
System.out.println("Playing " + title + " by " + artist);
}
}
之前注解装配方式里CDPlayerConfig只是通过注解来扫描组件,这里通过JavaConfig方式,显式装配CDPlayer和CompactDisc
正常通过JavaConfig装配bean最简单的方法是引用创建bean的方法,比如:
@Bean
public CDPlayer cdPlayer(CompactDisc yesterday) {
return new CDPlayer(yesterday);
}
这里使用@Bean注解,表明这个方法会创建一个bean实例,并将其注册到Spring应用上下文 中
CDPlayer()方法请求一个CompactDisc座位参数,当Spring调用CDPlayer()创建CDPlayer bean的时候,会自动装配一个CompactDisc到配置方法中,然后方法体可以按照合适的方法来使用它,这样CDPlayer()方法可以将CompactDisc注入到CDPlayer的构造函数中,而且不用明确引用CompactDisc的@Bean方法
package com.maoxiaomeng.javaconfig;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* Copyright (C), 2014-2018, maoxiaomeng.com
* FileName: CDPlayerConfig
* Author: lihui
* Date: 2018/6/22 下午11:09
*/
@Configuration
public class CDPlayerConfig {
@Bean
public CompactDisc yesterday() {
return new Yesterday();
}
@Bean
public CDPlayer cdPlayer(CompactDisc yesterday) {
return new CDPlayer(yesterday);
}
}
这种方法引用其他的bean,不会要求将CompactDisc声明到同一个配置类之中,在这里甚至没有要求CompactDisc必须要在JavaConfig中声明,可以通过组件扫描自动发现或者通过XML进行配置;可以将配置分散到多个配置类,XML文件以及自动扫描和装配bean之中,只要功能完整即可;不管CompactDisc采用什么方式创建出来,Spring都会将其传入到配置方法中,并用来创建CDPlayer bean
最后是测试类
package com.maoxiaomeng.javaconfig;
import junit.framework.TestCase;
import org.junit.Rule;
import org.junit.Test;
import org.junit.contrib.java.lang.system.StandardOutputStreamLog;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.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 class CDPlayerTest extends TestCase {
@Rule
public final StandardOutputStreamLog log = new StandardOutputStreamLog();
@Autowired
private MediaPlayer player;
@Test
public void play() {
player.play();
assertEquals(
"Playing Yesterday Once More by Carpenters\n",
log.getLog());
}
}
带有@Bean注解的方法可以采用任何必要的Java功能来产生bean实例