# 自动化装配 bean(@Component、@ComponentScan 和 @Autowired)
```java
package soundsystem;
public interface CompactDisc {
void play();
}
```
```java
package soundsystem;
import org.springframework.stereotype.Component;
@Component
public class SgtPeppers implements CompactDisc {
private String title = "title";
private String artist = "artist";
@Override
public void play() {
System.out.println("Playing " + title + " by " + artist);
}
}
```
@Component
表明类 CompactDisc
是一个组件类,默认 ID 为 sgtPeppers
。也可以指定 bean 的 ID, @Component("LonelyHeartsClub")
将 ID 指定为 lonelyHeartsClub
。 @Named
也可以来设置 bean 的 ID, @Named("lonelyHeartsClub")
,两者差别不大。
```java
package soundsystem;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
@Configuration
@ComponentScan
public class CDPlayerConfig {
}
```
@ComponentScan
启用组件扫描,默认扫描与配置类相同的包。可以通过设置 @ComponentScan
的 value 值来设置组件扫描的包, @ComponentScan("soundsystem")
。可以设置多个包, ComponentScan(basePackages={"soundsystem", "package1"})
。也可以设置扫描的类, ComponentScan(basePackageClasses={CDPlayer.class, DVDPlayer.class})
测试,引入 Spring 和 Junit 的 jar 包 。
运行提示找不到 hamcrest 包,降低 Junit 版本或者加入 hamcrest 包,由于降低 Junit 版本之后和 spring 适配有问题,只好加入 hamrest 包了。
```java
package soundsystem;
import org.junit.Test;
import org.junit.Assert;
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 {
@Autowired
private CompactDisc compactDisc;
@Test
public void cdShouldNotBeNull() {
Assert.assertNotNull(compactDisc);
compactDisc.play();
}
}
```
@Autowired
可以将扫描到的 bean 装配到注解的地方,可以在类中的属性上注解,也可以在方法上注解。 @Autowired
的 required 属性默认为 true,当没有 bean 时,会报错。将 required 属性设置为 false, @Autowired(required=false)
,当没有匹配的 bean,这个 bean 就会处于未装配状态,不会报错。 @Inject
和 @Autowired
作用类似。
java private CompactDisc compactDisc; @Autowired public void setCompactDisc(CompactDisc compactDisc) { this.compactDisc = compactDisc; }
# 通过 Java 代码装配 bean (JavaConfig)
要装配的类:
```java
package soundsystem;
public class SgtPeppers {
private String title = "title";
private String artist = "artist";
@Override
public void play() {
System.out.println("Playing " + title + " by " + artist);
}
}
```
```java
package soundsystem;
public class CDPlayer {
private CompactDisc compactDisc;
public CDPlayer(CompactDisc compactDisc) {
this.compactDisc = compactDisc;
}
public void play() {
compactDisc.play();
}
}
```
配置类:
```java
package soundsystem;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class CDPlayerConfig {
@Bean
public CompactDisc sgtPeppers() {
return new SgtPeppers();
}
@Bean
public CDPlayer cdPlayer() {
return new CDPlayer(sgtPeppers());
}
}
```
测试类:
```java
package soundsystem;
import org.junit.Test;
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 {
@Autowired
private CDPlayer cdPlayer;
@Test
public void cdShouldNotBeNull() {
cdPlayer.play();
}
}
```
@Bean 装配 bean,配置类中,也可以用如下方式进行装配。在装配 CDPlayer 过程中,可以由 sgtPeppers () 或 CompactDisc compactDisc 找到装配的 CompactDisc 的 bean,并注入到 cdPlayer () 方法中。
# 通过 XML 装配 bean
xml 配置:
```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"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:jee="http://www.springframework.org/schema/jee"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.3.xsd
http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-3.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd">
<bean id="compactDisc" class="soundsystem.SgtPeppers"></bean>
<bean id="cdPlayer" class="soundsystem.CDPlayer">
<constructor-arg ref="compactDisc"></constructor-arg>
</bean>
</beans>
```
<constructor-arg>
元素向 CDPlayer 中注入 CompactDisc
的 bean,也可以使用 c - 命名空间。
```xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:c="http://www.springframework.org/schema/c"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:jee="http://www.springframework.org/schema/jee"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.3.xsd
http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-3.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd
">
<bean id="compactDisc" class="soundsystem.SgtPeppers"></bean>
<bean id="cdPlayer" class="soundsystem.CDPlayer" c:_0-ref="compactDisc"></bean>
</beans>
```
开始测试,在测试类中引用 xml 文件。使用 ClassPathXmlApplicationContext 和 FileSystemXmlApplicationContext 无法载入 spring 容器,原因未知。
```java
package soundsystem;
import org.junit.Test;
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({"/soundsystem/bean.xml"})
public class CDPlayerTest {
@Autowired
private CDPlayer cdPlayer;
@Test
public void cdShouldNotBeNull() {
cdPlayer.play();
}
}
```
当类 SgtPeppers 的两个属性需要传入值时,即:
```java
package soundsystem;
public class SgtPeppers implements CompactDisc {
private String title;
private String artist;
public SgtPeppers(String title, String artist) {
this.title = title;
this.artist = artist;
}
@Override
public void play() {
System.out.println("Playing " + title + " by " + artist);
}
}
```
配置文件中装配 SgtPeppers 时需要传入参数的值:
```xml
<bean id="compactDisc" class="soundsystem.SgtPeppers">
<constructor-arg value="title" />
<constructor-arg value="artist" />
</bean>
```
这里也可以用 c - 命名空间:
```xml
<bean id="compactDisc" class="soundsystem.SgtPeppers" c:title="title" c:artist="artist"></bean>
```
或:
```xml
<bean id="compactDisc" class="soundsystem.SgtPeppers" c:_0="title" c:_1="artist"></bean>
```
当类 SgtPeppers 的属性存在集合时,即:
```java
package soundsystem;
import java.util.List;
public class SgtPeppers implements CompactDisc {
private String title;
private String artist;
private List<String> tracks;
public SgtPeppers(String title, String artist, List<String> tracks) {
this.title = title;
this.artist = artist;
this.tracks = tracks;
}
@Override
public void play() {
System.out.println("Playing " + title + " by " + artist);
tracks.stream().forEach(System.out::println);
}
}
```
配置文件中需要传入 List 的值:
```xml
<bean id="compactDisc" class="soundsystem.SgtPeppers">
<constructor-arg value="title"></constructor-arg>
<constructor-arg value="artist"></constructor-arg>
<constructor-arg>
<list>
<value>s1</value>
<value>s2</value>
<value>s3</value>
<value>s4</value>
</list>
</constructor-arg>
</bean>
```
c - 命名空间的弱势就在于此,它无法做到加入集合的值。
以上的类 CDPlayer 是通过构造函数注入 compactDisc 的 bean,也可以通过 setter 方法注入。
```java
package soundsystem;
import org.springframework.beans.factory.annotation.Autowired;
public class CDPlayer {
private CompactDisc compactDisc;
@Autowired
public void setCompactDisc(CompactDisc compactDisc) {
this.compactDisc = compactDisc;
}
public void play() {
compactDisc.play();
}
}
```
xml <bean id="cdPlayer" class="soundsystem.CDPlayer"> <property name="compactDisc" ref="compactDisc"></property> </bean>
也可以使用 p - 命名空间注入 compactDisc,xml 头部加入 xmlns:p="http://www.springframework.org/schema/p"
。
```xml
<bean id="cdPlayer" class="soundsystem.CDPlayer" p:compactDisc-ref="compactDisc"></bean>
```
p - 命名空间也可以注入普通属性:
```xml
<bean id="compactDisc" class="soundsystem.SgtPeppers" p:title="title" p:artist="artist"></bean>
```
但不能注入集合,可以通过 <util:list>
元素注入集合的值,头部需要引入 util。
```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"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd">
<bean id="compactDisc" class="soundsystem.SgtPeppers" p:title="title" p:artist="artist" p:tracks-ref="trackList"></bean>
<util:list id="trackList">
<value>s1</value>
<value>s2</value>
<value>s3</value>
</util:list>
<bean id="cdPlayer" class="soundsystem.CDPlayer" p:compactDisc-ref="compactDisc"></bean>
</beans>
```
# 导入和混合配置
在 JavaConfig 中引用 JavaConfig 配置
package soundsystem;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.ArrayList;
import java.util.List;
@Configuration
public class SgtConfig {
@Bean
public CompactDisc sgtPeppers() {
List<String> tracks = new ArrayList<>();
tracks.add("s1");
tracks.add("s2");
tracks.add("s3");
return new SgtPeppers("title", "artist", tracks);
}
}
```java
package soundsystem;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
@Configuration
@Import(SgtConfig.class)
public class CDPlayerConfig {
@Bean
public CDPlayer cdPlayer(CompactDisc compactDisc) {
return new CDPlayer(compactDisc);
}
}
```
- 在 JavaConfig 中引用 XML 配置
SgtPeppers 通过 xml 装配,CDPlayer 通过 JavaConfig 装配,在 CDPlayerConfig 中引用 xml 的装配。
```xml
<bean id="compactDisc" class="soundsystem.SgtPeppers" c:title="title" c:artist="artist">
<constructor-arg>
<list>
<value>s1</value>
<value>s2</value>
<value>s3</value>
</list>
</constructor-arg>
</bean>
```
```java
package soundsystem;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ImportResource;
@Configuration
@ImportResource("/soundsystem/bean.xml")
public class CDPlayerConfig {
@Bean
public CDPlayer cdPlayer(CompactDisc compactDisc) {
return new CDPlayer(compactDisc);
}
}
```
- 在 XML 配置中引用 JavaConfig
SgtPeppers 通过 JavaConfig 装配,CDPlayer 通过 xml 装配,在 bean.xml 中引用 SgtConfig 的装配。
```java
package soundsystem;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.ArrayList;
import java.util.List;
@Configuration
public class SgtConfig {
@Bean
public CompactDisc sgtPeppers() {
List<String> tracks = new ArrayList<>();
tracks.add("s1");
tracks.add("s2");
tracks.add("s3");
return new SgtPeppers("title", "artist", tracks);
}
}
```
```xml
<bean class="soundsystem.SgtConfig"></bean>
<bean id="cdPlayer" class="soundsystem.CDPlayer" c:_0-ref="sgtPeppers"></bean>
```
- 在 XML 配置中引用 XML
sgt-bean.xml
```xml
<bean id="sgtPeppers" class="soundsystem.SgtPeppers" c:title="title" c:artist="artist">
<constructor-arg>
<list>
<value>s1</value>
<value>s2</value>
<value>s3</value>
</list>
</constructor-arg>
</bean>
```
cdPlayer-bean.xml
```xml
<import resource="sgt-bean.xml"></import>
<bean id="cdPlayer" class="soundsystem.CDPlayer" c:_0-ref="sgtPeppers"></bean>
```