# 自动化装配 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>    
```