装配
自动装配
装配文件
- 装配文件是java文件,必须要有标签@Configuration和@ComponentScan,该类需要放在被扫描的其他类文件的同级目录
- 如果装配文件不放到被扫描文件的同级目录,可以通过@ComponentScan("${packagename}"),来扫描指定包
- @ComponentScan也可以指定basePackages或basePackageClasses,尤其是后者可以通过结合标记接口文件的方式来避免出错
package soundsystem;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
/**
* @Description CdPlayerConfig
* @Author sunzhilong
* @Since 2021/04/05
**/
@Configuration
@ComponentScan
public class CdPlayerConfig {
}
被装配文件
package soundsystem;
/**
* @Description CompactDisc
* @Author sunzhilong
* @Since 2021/04/05
**/
public interface CompactDisc {
void play();
}
package soundsystem;
import org.springframework.stereotype.Component;
/**
* @Description SgtPeppers
* @Author sunzhilong
* @Since 2021/04/05
**/
@Component
public class SgtPeppers implements CompactDisc {
private String title = "Sgt. Pepper's Lonely Hearts Club Band";
private String artist = "The Beatles";
@Override
public void play() {
System.out.print("Playing " + title + " by " + artist);
}
}
package soundsystem;
/**
* @author cooper
*/
public interface MediaPlayer {
void play();
}
package soundsystem;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
/**
* @Description CDPlayer
* @Author sunzhilong
* @Since 2021/04/05
**/
@Component
public class CdPlayer implements MediaPlayer{
@Autowired
private CompactDisc disc;
@Override
public void play() {
disc.play();
}
}
验证
package soundsystem;
import junit.framework.TestCase;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.contrib.java.lang.system.SystemOutRule;
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;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = CdPlayerConfig.class)
public class SgtPeppersTest {
@Rule
public final SystemOutRule log = new SystemOutRule();
@Autowired
private MediaPlayer player;
@Autowired
private CompactDisc cd;
@Before
public void before() {
log.enableLog();
}
@Test
public void cdShouldNotBeNull() {
TestCase.assertNotNull(cd);
}
@Test
public void play() {
player.play();
TestCase.assertEquals(
"Playing Sgt. Pepper's Lonely Hearts Club Band by The Beatles",
log.getLog());
}
}
这里的SystemOutRule需要开启enableLog(),来接收输出,上边的两个标签也至关重要
-
pom文件
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.cooper.spring.in.action</groupId> <artifactId>assembling</artifactId> <version>1.0-SNAPSHOT</version> <properties> <maven.compiler.source>14</maven.compiler.source> <maven.compiler.target>14</maven.compiler.target> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <spring.version>5.3.4</spring.version> <junit.version>4.12</junit.version> <system.rules.version>1.19.0</system.rules.version> </properties> <dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>${junit.version}</version> <scope>test</scope> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-test</artifactId> <version>${spring.version}</version> <scope>test</scope> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context-support</artifactId> <version>${spring.version}</version> <scope>test</scope> </dependency> <dependency> <groupId>com.github.stefanbirkner</groupId> <artifactId>system-rules</artifactId> <version>${system.rules.version}</version> <scope>test</scope> </dependency> </dependencies> </project>
javaconfig
装配文件
- 同样的@Configuration表示这是一个装配文件
- 这的@Bean用来创建单例bean,方法名就是单例的Id
- @Bean创建出来的单例Id是按照类型传给别的方法的,并不要求参数名相同
package soundsystem;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
/**
* @Description CdPlayerConfig
* @Author sunzhilong
* @Since 2021/04/05
**/
@Configuration
public class CdPlayerConfig {
@Bean
public CompactDisc compactDisc() {
return new SgtPeppers();
}
@Bean
public CdPlayer cdPlayer(CompactDisc compactDisc) {
return new CdPlayer(compactDisc);
}
}
被装配文件
package soundsystem;
/**
* @Description CompactDisc
* @Author sunzhilong
* @Since 2021/04/05
**/
public interface CompactDisc {
void play();
}
package soundsystem;
/**
* @Description SgtPeppers
* @Author sunzhilong
* @Since 2021/04/05
**/
public class SgtPeppers implements CompactDisc {
private String title = "Sgt. Pepper's Lonely Hearts Club Band";
private String artist = "The Beatles";
@Override
public void play() {
System.out.print("Playing " + title + " by " + artist);
}
}
package soundsystem;
/**
* @author cooper
*/
public interface MediaPlayer {
void play();
}
package soundsystem;
/**
* @Description CDPlayer
* @Author sunzhilong
* @Since 2021/04/05
**/
public class CdPlayer implements MediaPlayer {
private CompactDisc disc;
public CdPlayer(CompactDisc disc) {
this.disc = disc;
}
@Override
public void play() {
disc.play();
}
}
- 可以看到被装配文件少了@Autowired和@Component标签
验证
package soundsystem;
import static org.junit.Assert.*;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.contrib.java.lang.system.StandardOutputStreamLog;
import org.junit.contrib.java.lang.system.SystemOutRule;
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;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = CdPlayerConfig.class)
public class CDPlayerTest {
@Rule
public final SystemOutRule log = new SystemOutRule();
@Autowired
private MediaPlayer player;
@Before
public void before() {
log.enableLog();
}
@Test
public void play() {
player.play();
assertEquals(
"Playing Sgt. Pepper's Lonely Hearts Club Band by The Beatles",
log.getLog());
}
}
- 这里依然用了@Autowired来为变量注入,也能成功,让人感到奇怪,看来@SpringJUnit4ClassRunner标签还是很厉害的
xml装配
引用方式
引用方式是最常见的一种引用方式
被装配文件
package soundsystem;
public interface MediaPlayer {
void play();
}
package soundsystem;
public class CDPlayer implements MediaPlayer {
private CompactDisc cd;
public CDPlayer(CompactDisc cd) {
this.cd = cd;
}
@Override
public void play() {
cd.play();
}
}
package soundsystem;
public interface CompactDisc {
void play();
}
package soundsystem;
public class SgtPeppers implements CompactDisc {
private String title = "Sgt. Pepper's Lonely Hearts Club Band";
private String artist = "The Beatles";
@Override
public void play() {
System.out.print("Playing " + title + " by " + artist);
}
}
验证
package soundsystem;
import junit.framework.TestCase;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.contrib.java.lang.system.SystemOutRule;
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;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration
public class ConstructorArgReferenceTest {
@Rule
public final SystemOutRule log = new SystemOutRule();
@Autowired
private MediaPlayer player;
@Before
public void before() {
log.enableLog();
}
@Test
public void play() {
player.play();
TestCase.assertEquals(
"Playing Sgt. Pepper's Lonely Hearts Club Band by The Beatles",
log.getLog());
}
}
配置文件
验证时需要相应的xml文件,注意文件在测试的resources中的soundsystem目录下,以ConstructorArgReferenceTest-context.xml命名的文件中
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="compactDisc" class="soundsystem.SgtPeppers"/>
<bean id="cdPlayer" class="soundsystem.CDPlayer">
<constructor-arg ref="compactDisc"/>
</bean>
</beans>
很显然测试类中的@ContextConfiguration标签起到了查找xml所在位置的能力,默认是同目录的位置的对应测试类名开头以-context结尾的xml文件,如果不在同目录下将会报异常
4月 07, 2021 12:32:16 上午 org.springframework.test.context.support.AbstractContextLoader generateDefaultLocations
信息: Could not detect default resource locations for test class [soundsystem.ConstructorArgReferenceTest]: no resource found for suffixes {-context.xml}.
4月 07, 2021 12:32:16 上午 org.springframework.test.context.support.AnnotationConfigContextLoaderUtils detectDefaultConfigurationClasses
信息: Could not detect default configuration classes for test class [soundsystem.ConstructorArgReferenceTest]: ConstructorArgReferenceTest does not declare any static, non-private, non-final, nested classes annotated with @Configuration.
java.lang.IllegalStateException: DelegatingSmartContextLoader was unable to detect defaults, and no ApplicationContextInitializers or ContextCustomizers were declared for context configuration attributes [[ContextConfigurationAttributes@6b57696f declaringClass = 'soundsystem.ConstructorArgReferenceTest', classes = '{}', locations = '{}', inheritLocations = true, initializers = '{}', inheritInitializers = true, name = [null], contextLoaderClass = 'org.springframework.test.context.ContextLoader']]
引用值方式
被装配文件
package soundsystem;
public interface MediaPlayer {
void play();
}
package soundsystem;
public class CDPlayer implements MediaPlayer {
private CompactDisc cd;
public CDPlayer(CompactDisc cd) {
this.cd = cd;
}
@Override
public void play() {
cd.play();
}
}
package soundsystem;
public interface CompactDisc {
void play();
}
package soundsystem;
public class BlankDisc implements CompactDisc {
private String title;
private String artist;
public BlankDisc(String title, String artist) {
this.title = title;
this.artist = artist;
}
@Override
public void play() {
System.out.print("Playing " + title + " by " + artist);
}
}
验证
package soundsystem;
import junit.framework.TestCase;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.contrib.java.lang.system.SystemOutRule;
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;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration
public class ConstructorArgValueTest {
@Rule
public final SystemOutRule log = new SystemOutRule();
@Autowired
private MediaPlayer player;
@Before
public void before() {
log.enableLog();
}
@Test
public void play() {
player.play();
TestCase.assertEquals(
"Playing Sgt. Pepper's Lonely Hearts Club Band by The Beatles",
log.getLog());
}
}
配置文件
配置文件规则要求和上述相同
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="compactDisc"
class="soundsystem.BlankDisc">
<constructor-arg value="Sgt. Pepper's Lonely Hearts Club Band"/>
<constructor-arg value="The Beatles"/>
</bean>
<bean id="cdPlayer"
class="soundsystem.CDPlayer">
<constructor-arg ref="compactDisc"/>
</bean>
</beans>
c命名空间引用
被装配文件
和直接引用Id方式相同
验证
package soundsystem;
import junit.framework.TestCase;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.contrib.java.lang.system.SystemOutRule;
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;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration
public class CNamespaceReferenceTest {
@Rule
public final SystemOutRule log = new SystemOutRule();
@Autowired
private MediaPlayer player;
@Before
public void before() {
log.enableLog();
}
@Test
public void play() {
player.play();
TestCase.assertEquals(
"Playing Sgt. Pepper's Lonely Hearts Club Band by The Beatles",
log.getLog());
}
}
配置文件
既然是C命名空间就要有xmlns:c=“http://www.springframework.org/schema/c”
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:c="http://www.springframework.org/schema/c"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="compactDisc" class="soundsystem.SgtPeppers"/>
<bean id="cdPlayer" class="soundsystem.CDPlayer"
c:cd-ref="compactDisc"/>
</beans>
p命名空间引用
被装配文件
package soundsystem;
public class BlankDisc implements CompactDisc {
private String title;
private String artist;
public BlankDisc(String title, String artist) {
this.title = title;
this.artist = artist;
}
@Override
public void play() {
System.out.print("Playing " + title + " by " + artist);
}
}
package soundsystem.properties;
import org.springframework.beans.factory.annotation.Autowired;
import soundsystem.CompactDisc;
import soundsystem.MediaPlayer;
public class CDPlayer implements MediaPlayer {
private CompactDisc compactDisc;
@Autowired
public void setCompactDisc(CompactDisc compactDisc) {
this.compactDisc = compactDisc;
}
@Override
public void play() {
compactDisc.play();
}
}
验证
package soundsystem;
import junit.framework.TestCase;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.contrib.java.lang.system.SystemOutRule;
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;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration
public class PNamespaceRefTest {
@Rule
public final SystemOutRule log = new SystemOutRule();
@Autowired
private MediaPlayer player;
@Before
public void before() {
log.enableLog();
}
@Test
public void play() {
player.play();
TestCase.assertEquals(
"Playing Sgt. Pepper's Lonely Hearts Club Band by The Beatles",
log.getLog());
}
}
配置文件
配置文件中要与p命名空间的规范引入:xmlns:p=“http://www.springframework.org/schema/p”
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="compactDisc" class="soundsystem.BlankDisc">
<constructor-arg value="Sgt. Pepper's Lonely Hearts Club Band"/>
<constructor-arg value="The Beatles"/>
</bean>
<bean id="cdPlayer" class="soundsystem.properties.CDPlayer">
<property name="compactDisc" ref="compactDisc"/>
</bean>
</beans>