Spring:Java配置类装配Bean

注解自动化是一种隐式装配方式,当自动化装配方案行不通的时候,可以考虑通过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实例

发表回复