Spring提供了三种主要的装配机制:
(1)在XML中进行显式配置
(2)在Java中进行显式配置
(3)隐式的bean发现机制和自动装配
一、自动化装配bean:
Spring从两个角度来实现自动化装配:
(1)组件扫描(component-scan):Spring会自动发现应用上下文中所创建的bean
(2)自动装配(autowiring):Spring自动满足bean之间的依赖
POJO:
//CD的一个接口
public interface CompactDisc {
void play();
}
@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.println("Playing "+title+" by "+artist);
}
}
@Configuration
//组件扫描默认是不启用的,所以需要使用该注解开启;
// @ComponentScan默认会扫描与配置类相同的包以及这个包下的所有子包,查找带有@Component注解的类。
@ComponentScan
public class CDPlayerConfig {
}
maven:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>4.3.23.RELEASE</version>
</dependency>
测试:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = CDPlayerConfig.class)
public class CDPlayerTest {
@Autowired
private CompactDisc cd;
@Test
public void cdShouldNotBeNull(){
Assert.notNull(cd,"cd Should Not Be Null !!!");
System.out.println(cd);
}
}
二、显式装配:
尽管在很多场景下通过组件扫描和自动装配实现Spring的自动化配置是更为推荐的方式,但有时候自动化配置的方案行不通,因此需要明确配置Spring。比如说,你想要将第三方库中的组件装配到你的应用中,在这种情况下,是没有办法在它的类上添加@Component和@Autowired注解的,因此就不能使用自动化装配的方案了。
在这种情况下,你必须要采用显式装配的方式。在进行显式配置的时候,有两种可选方案:Java和XML。在进行显式配置时,JavaConfig是更好的方案,因为它更为强大、类型安全并且对重构友好。
(1)Java Config示例
该选择构造器注入还是属性注入呢?作为一个通用的规则,对强依赖使用构造器注入,而对可选性的依赖使用属性注入
@Configuration
public class CDPlayerConfig {
@Bean
public Quest quest(){
SlayDragonQuest slayDragonQuest = new SlayDragonQuest(System.out);
return slayDragonQuest;
}
//直接通过构造器注入
@Bean
public Knight knight1(Quest quest){
BraveKnight braveKnight = new BraveKnight(quest);
return braveKnight;
}
//通过调用方法返回值注入,虽然此处调用了quest()方法,但是由于spring拦截器的作用,实际生成的只有一个Quest的实例(单例)
@Bean
public Knight knight2(){
BraveKnight braveKnight = new BraveKnight(quest());
return braveKnight;
}
//如果有多个构造方法,可以使用set方法或者其他方法注入
}
(2)XML注入示例
public class BlankDisc implements CompactDisc{
private String title;
private String artist;
private List<String> tracks;
private List<Object> objectList;
public BlankDisc() {
}
public BlankDisc(String title, String artist, List<String> tracks, List<Object> objectList) {
this.title = title;
this.artist = artist;
this.tracks = tracks;
this.objectList = objectList;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
@Override
public void play() {
System.out.println("Playing "+title+" by "+artist);
for (String track : tracks) {
System.out.println("-Track: "+track);
}
}
}
<?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:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<bean id="obj" class="java.lang.Object"></bean>
<beans>
<bean id="compactDisc" class="com.chapter2.BlankDisc">
<!--可以通过artist或者index都行-->
<constructor-arg index="0" name="title" value="Sgt.Pepper's Lonely Hearts Club Band"/>
<constructor-arg index="1" name="artist" value="The Beatles"/>
<constructor-arg index="2" name="tracks">
<!--注入实际value到list属性-->
<list>
<value>Sgt.Pepper's Lonely Hearts Club Band</value>
<value>With a Little Help from My Friends</value>
<value>Lucy in the Sky with Diamonds</value>
<value>Getting Better</value>
<value>Fixing a Hole</value>
<!--...-->
</list>
</constructor-arg>
<!--注入引用列表-->
<constructor-arg name="objectList">
<list>
<ref bean="obj"></ref>
</list>
</constructor-arg>
</bean>
<bean id="compactDisc2" class="com.chapter2.BlankDisc">
<property name="title" value=""/>
</bean>
</beans>
</beans>
JavaConfig、@ComponentScan、xml等注入方式可以同时结合使用,优先推荐自动扫描和JavaConfig:
@Configuration
public class CDConfig {
@Bean
public CompactDisc compactDisc(){
return new SgtPeppers();
}
}
@Configuration
public class CDPlayerConfig {
@Bean
public CDPlayer cdPlayer(CompactDisc compactDisc){
return new CDPlayer(compactDisc);
}
}
@Configuration
public class QuestConfig {
@Bean
public Quest quest(){
Quest slayDragonQuest = new SlayDragonQuest(System.out);
return slayDragonQuest;
}
}
@Configuration
@Import({QuestConfig.class})
public class KnightConfig {
@Bean
public Knight knight1(Quest quest){
Knight braveKnight = new BraveKnight(quest);
return braveKnight;
}
}
使用@ImportResource标签可以在JavaConfig中引入xml文件
@Configuration
//使用ImportResource标签引入xml配置文件
@ImportResource({"classpath:/META-INF/spring/spring.xml"})
public class XmlConfig {
}
可以在一个或者多个JavaConfig根据用途或者结构把相关的JavaConfig配置类通过@Import归类到一个配置类中
@Configuration
//通过@Import注解将多个配置结合到一起,这些配置就可以互相引用了,也可以在用到其他config的类上单独import
@Import({QuestConfig.class, KnightConfig.class})
public class Chapter1Config {
}
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = {Chapter1Config.class, Chapter2Config.class, XmlConfig.class})
public class CDPlayerTest {
}