Spring学习笔记-装配Bean

本章内容:

  • 声明bean
  • 构造器注入和Setter方法注入
  • 装配bean
  • 控制bean的创建和销毁

在Spring中,对象无需自己查找或创建与其所关联的对象,容器负责把需要相互协作的对象引用赋值给各个对象,这种协作关系成为装配


2.1 Spring配置的可选方案

Spring容器负责创建应用程序中的bean并通过DI来协调对象之间的关系。开发人员需要做的是告诉Spring需要创建哪些对象并且如何装配在一起。

Spring提供了三种可选方式:

  • XML配置
  • Java显式配置
  • 隐式的bean发现机制和自动装配

如何选择:尽可能使用自动配置机制,当必须显式配置时使用JavaConfig,当JavaConfig中没有同样实现时使用XML配置。


2.2 自动化装配bean

  • 自动扫描
  • 自动装配

2.2.1 创建可被发现的bean

1
2
3
4
5
6
7
8
9
10
package com.kotobuki2.soundsys;

/**
* @author zhulongkun20@163.com
* @since 2018/11/17 下午7:21
*/
public interface CompactDisc {
void play();
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package com.kotobuki2.soundsys;

import org.springframework.stereotype.Component;

/**
* @author zhulongkun20@163.com
* @since 2018/11/17 下午7:22
*/
@Component
public class SgtPeppers implements CompactDisc {
private String title = "SgtPeppers title";
private String artiest = "The Beatles";

@Override
public void play() {
System.out.println("playing..");
}
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
package com.kotobuki2.soundsys;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

/**
* @author zhulongkun20@163.com
* @since 2018/11/17 下午7:24
*/
@Configuration
@ComponentScan
public class CDPlayerConfig {
}

通过XML配置开启注解扫描:

1
<context:component-scan base-package="soundsys"/>

自动装配测试:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
package com.test;

import com.kotobuki2.soundsys.CDPlayerConfig;
import com.kotobuki2.soundsys.CompactDisc;
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;

import static org.junit.Assert.assertNotNull;

/**
* @author zhulongkun20@163.com
* @since 2018/11/17 下午7:28
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = CDPlayerConfig.class)
public class CDPlayerTest {
@Autowired
private CompactDisc compactDisc;

@Test
public void cdTest() {
assertNotNull(compactDisc);
}
}

2.2.2 为组件扫描的bean命名

默认将类名第一个字母小写后的字符串作为bean的id。

可以通过注解标示bean的别名:

1
@Component("alias")

2.2.3 设置组件扫描的基础包

默认以配置类所在的包为基础包进行扫描。

自定义扫描包:

1
2
3
4
@Configuration
@ComponentScan("package-name")
//扫描多个基础包
@ComponentScan(basePackages = {"package1", "package2"})

但是用直接指定包名会出现问题:包名被变更以后便无法扫描到所需要的类,因此,还有另一种指定扫描包的方法:

1
2
@Configuration
@ComponentScan(basePackageClasses = {CDPlayer.class, DVDPlayer.class})

这种方式下,这些类所在的包都会作为基础包进行扫描,即便代码重构也不会受到影响。

2.2.4 通过为bean添加注解实现自动装配

1
2
3
4
5
6
7
8
9
10
package com.kotobuki2.soundsys;

/**
* @author zhulongkun20@163.com
* @since 2018/11/17 下午8:51
*/
public interface MediaPlayer {
void play();
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
package com.kotobuki2.soundsys;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

/**
* @author zhulongkun20@163.com
* @since 2018/11/17 下午8:50
*/
@Component
public class CDPlayer implements MediaPlayer {
private CompactDisc compactDisc;

@Autowired
public CDPlayer(CompactDisc compactDisc) {
this.compactDisc = compactDisc;
}

@Override
public void play() {
compactDisc.play();
}
}

@Autowired注解不仅能够用在构造器上,也能用在属性的Setter方法上。


2.3 通过Java装配bean

在进行显式配置的时候,JavaConfig是更好的方案,因为其强大、类型安全并且重构友好。因为其本身就是Java代码。

声明简单的bean:

1
2
3
4
@Bean(name="alias")
public CompactDisc sgtPeppers() {
return new SgtPeppers();
}

借助JavaConfig实现注入:

1
2
3
4
5
6
7
8
9
@Bean
public CDPlayer cdPlayer(){
return CDPlayer(new sgtPeppers());
}

@Bean
public CDPlayer cdPlayer(CompactDisc disc){
return new CDplayer(disc);
}

后者不要求disc必须在JavaConfig中声明,实际上它可以通过组件扫描功能自动发现或者XML来进行配置。

通过构造器注入:

1
2
3
4
5
6
@Bean
public CDPlayer cdPlayer(CompactDisc disc){
CDPlayer cdPlayer = new CDPlayer(disc);
cdPlayer.setCompactDisc(disc);
return cdPlayer;
}

2.4 通过XML装配Bean

在XML配置中,需要创建一个以作为根元素的XML配置文件。

可以借助Spring Tool Suite创建和管理Spring XML配置文件

2.4.1 声明一个简单的bean:

1
<bean id="bean_id" class="com.soundsys.SgtPeppers" />

如果没有指明id,bean将会根据类全限定名指定,为了减少XML配置的繁琐,只需要对需要按名称引用的bean进行命名。“com.soundsys.SgtPeppers#0”…

元素:

1
2
3
<bean id="cdPlayer" class="com.soundsys.CDPlayer">
<constructor-arg ref="compactDisc" />
</bean>

2.4.2 c命名空间

p命名空间和c命名空间

2.4.3 将字面量注入到构造器中:

1
2
3
4
<bean id="compactDisc" class="com.soundsys.BlackDisc">
<constructor-arg value="title" />
<constructor-arg value="The Beatles" />
</bean>

使用 value 属性,将给定的值注入到构造器中。

2.4.3 装配集合

1
2
3
4
5
6
7
8
9
10
<bean id="beat" class="com.soundsys.beat">
<constructor-arg value="The Beatles"/>
<constructor-arg>
<list>
<ref bean="bean1"/>
<ref bean="bean2"/>
<ref bean="bean3"/>
</list>
</constructor-arg>
</bean>

或者

1
2
3
4
5
6
7
8
9
<bean id="beat" class="com.soundsys.beat">
<constructor-arg value="The Beatles"/>
<constructor-arg>
<set>
<value>SgtPeppers</value>
<value>The Beatles</value>
</set>
</constructor-arg>
</bean>

使用两者的区别就是 list 和 set 会忽略重复元素。

2.4.4 p命名空间

p命名空间和c命名空间

2.4.5 导入混合配置

在 JavaConfig 中引用 JavaConfig 配置:

1
2
3
4
5
6
7
8
@Configuration
@Import(CDConfig.class)
public class CDPlayerConfig {
@Bean
public CDPlayer cdPlayer(CompactDisc disc) {
return new CDPlayer(disc);
}
}

或者:

1
2
3
4
@Configuration
@Import(CDPlayerConfig.class, CDConfig.class)
public class SoundSysConfig {
}

新建一个配置类,使用@Import导入两个配置类。

在JavaConfig中引入XML配置:

1
2
3
4
5
@Configuration
@Import(CDPlayerConfig.class)
@ImportResource("classpath:cd-config.xml")
public class SoundSysConfig {
}

在XML配置中引用XML配置:

1
2
3
4
<beans>
<import resource="cd-config.xml"/>
<bean id="cdPlayer" class="com.soundsys.CDPlayer" c:cd-ref="compactDisc">
</beans>

在XML中引入JavaConfig配置:

1
2
3
4
<beans>
<bean class="com.soundsys.CDConfig"/>
<bean id="cdPlayer" class="com.soundsys.CDPlayer" c:cd-ref="compactDisc"/>
</beans>

或者:

1
2
3
4
<beans>
<bean class="com.soundsys.CDConfig"/>
<import resource="cdplayer-config.xml"/>
</beans>

新建一个配置文件,分别导入JavaConfig配置和XML配置。


小结

Spring框架的核心是Spring容器,负责管理应用中组件的生命周期,它会创建这些组件并保证它们的依赖能够得到满足。

尽可能使用自动配置,以避免显式配置带来的维护成本。

如果确实需要显式配置,应优先选择基于Java的配置,因为其更加强大、类型安全且易于重构。