导语:
依赖注入(DI)是Spring的最基本要素,而DI的本质是装配(wiring)。
装配就是创建应用对象之间协作关系的行为。
spring三种主要的装配bean机制:
在XML中进行显式配置
在Java中进行显式配置
隐式的bean发现机制和自动装配
一、在XML中进行显式配置
xml配置bean,意味着要创建一个XML文件,并且要以<beans>元素为根。
- 声明bean的方式(使用<bean>元素并指定class属性):
<bean class="com.du.Hello"/>
因为没有明确给定id,所以该bean的id会是“com.du.Hello#0”,如果声明了另一个Hello,那么它自动得到的id将会是“com.du.Hello#1”。
- 借助构造器注入初始化bean
在xml中声明DI时,有两种基本的配置方案:
- <constructor-arg>元素
使用Spring3.0所引入的c-命名空间
通过Spring的c-命名空间将bean引用注入到构造器参数中
c-命名空间是在Spring 3.0中引入的, 它是在XML中更为简洁地描述构造器参数的方式。 要使用它的话, 必须要在XML的顶部声明其模式, 如下所示:
声明c命名空间2.1构造器注入bean引用
使用ref属性来引用其它的bean
//<constructor-arg>元素
<bean id="cdPlayer" class="soundsystem.CDPlayer">
<constructor-arg ref="compactDisc" />
</bean>
//c-命名空间 ,有4种方式
1.
<bean id="cdPlayer" class="soundsystem.CDPlayer"
c:cd-ref="compactDisc" />
</beans>
2.
<bean id="cdPlayer" class="soundsystem.CDPlayer"
c:_-ref="compactDisc" />
</beans>
3.
<bean id="cdPlayer" class="soundsystem.CDPlayer"
c:_0-ref="compactDisc" />
</beans>
4.
<bean id="cdPlayer" class="soundsystem.CDPlayer"
c:_1-ref="compactDisc" />
</beans>
2.2将字面量注入到构造器中
//<constructor-arg>元素
<bean id="compactDisc"
class="soundsystem.BlankDisc">
<constructor-arg value="Sgt. Pepper's Lonely Hearts Club Band" />
<constructor-arg value="The Beatles" />
</bean>
//c-命名空间
引用构造器参数的名字引入字面量
<bean id="compactDisc" class="soundsystem.BlankDisc"
c:_title="Sgt. Pepper's Lonely Hearts Club Band"
c:_artist="The Beatles" />
通过参数索引装配相同的字面量值
<bean id="compactDisc" class="soundsystem.BlankDisc"
c:_0="Sgt. Pepper's Lonely Hearts Club Band"
c:_1="The Beatles" />
如果只有一个构造器参数的话,可以这样声明字面量值:
<bean id="cdPlayer" class="soundsystem.CDPlayer"
c:_="Sgt. Pepper's Lonely Hearts Club Band" />
2.3装配集合
- 使用<list>元素声明构造器属性
使用<value>元素指定列表中的元素值
<bean id="compactDisc" class="soundsystem.collections.BlankDisc">
<constructor-arg value="Sgt. Pepper's Lonely Hearts Club Band" />
<constructor-arg value="The Beatles" />
<constructor-arg>
<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>
<value>She's Leaving Home</value>
<value>Being for the Benefit of Mr. Kite!</value>
<value>Within You Without You</value>
<value>When I'm Sixty-Four</value>
<value>Lovely Rita</value>
<value>Good Morning Good Morning</value>
<value>Sgt. Pepper's Lonely Hearts Club Band (Reprise)</value>
<value>A Day in the Life</value>
</list>
</constructor-arg>
</bean>
使用<ref>元素实现bean引用列表的装配。
<bean id="compactDisc" class="soundsystem.collections.BlankDisc">
<constructor-arg value="Sgt. Pepper's Lonely Hearts Club Band" />
<constructor-arg value="The Beatles" />
<constructor-arg>
<list>
<ref bean="" />
<ref bean="" />
<ref bean="" />
...
</list>
</constructor-arg>
</bean>
-
也可以使用<set>元素:
<set>和<list>元素的区别不大, 其中最重要的不同在于当Spring创建要装配的集合时, 所创建的是java.util.Set还是java.util.List。 如果是Set的话, 所有重复的值都会被忽略掉, 存放顺序也不会得以保证。 不过无论在哪种情况下, <set>或<list>都可以用来装配List、 Set甚至数组。 -
使用c-命名空间的属性无法实现装配集合的功能,只能使用<constructor-arg>
- 设置属性
- <property>元素
p-命名空间
为了启用p-命名空间, 必须要在XML文件中与其他的命名空间一起对其进行声明:
声明p命名空间
- 装配bean引用:
//使用<property>元素:
<bean id="cdPlayer" class="soundsystem.properties.CDPlayer">
<property name="compactDisc" ref="compactDisc" />
</bean>
//使用p-命名空间:
<bean id="cdPlayer"
class="soundsystem.properties.CDPlayer"
p:compactDisc-ref="compactDisc" />
- 装配字面量:
//使用<property>元素:
<property name="artist" value="The Beatles" />
//使用p-命名空间:
p:artist="The Beatles"
- 使用<list>元素设置集合属性
//使用<property>元素:
<bean id="compactDisc"
class="soundsystem.properties.BlankDisc">
<property name="tracks">
<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>
<value>She's Leaving Home</value>
<value>Being for the Benefit of Mr. Kite!</value>
<value>Within You Without You</value>
<value>When I'm Sixty-Four</value>
<value>Lovely Rita</value>
<value>Good Morning Good Morning</value>
<value>Sgt. Pepper's Lonely Hearts Club Band (Reprise)</value>
<value>A Day in the Life</value>
</list>
</property>
</bean>
但需要注意的是, 我们不能使用p-命名空间来装配集合, 没有便利的方式使用p-命名空间来指定一个值(或bean引用) 的列表。 但是, 我们可以使用Spring util-命名空间中的一些功能来简化BlankDiscbean。
首先, 需要在XML中声明util-命名空间及其模式:
声明util命名空间
//使用util-命名空间功能之一<util:list>元素来装配集合:
<util:list id="trackList">
<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>
<value>She's Leaving Home</value>
<value>Being for the Benefit of Mr. Kite!</value>
<value>Within You Without You</value>
<value>When I'm Sixty-Four</value>
<value>Lovely Rita</value>
<value>Good Morning Good Morning</value>
<value>Sgt. Pepper's Lonely Hearts Club Band (Reprise)</value>
<value>A Day in the Life</value>
</util:list>
然后将此【集合】注入到bean的属性中:
- 使用<property>元素:
<property name="tracks" ref="trackList" />
- 使用p-命名空间
p:tracks-ref="trackList"
<util:list>只是util-命名空间中的多个元素之一,在需要的时候,可能会用到util-命名空间中的其它部分成员。
Spring util-命名空间中的元素:
<util:constant> 引用某个类型的public static域, 并将其暴露为bean
util:list 创建一个java.util.List类型的bean, 其中包含值或引用
util:map 创建一个java.util.Map类型的bean, 其中包含值或引用
util:properties 创建一个java.util.Properties类型的bean
util:property-path 引用一个bean的属性(或内嵌属性) , 并将其暴露为bean
util:set 创建一个java.util.Set类型的bean, 其中包含值或引用
二、在Java类中进行显式配置
创建JavaConfig类显示配置Spring:关键在于为其添加 @Configuration 注解。它包含在Spring应用上下文中如何创建bean的细节。
- 创建配置类
创建JavaConfig类的关键在于为其添加 @Configuration注解, @Configuration注解表明这个类是一个配置类, 该类应该包含在Spring应用上下文中如何创建bean的细节。 - 声明简单的bean
要在JavaConfig中声明bean, 我们需要编写一个方法, 这个方法会创建所需类型的实例, 然后给这个方法添加 @Bean注解。 比方说, 下面的代码声明了CompactDisc bean:
@Bean注解会告诉Spring这个方法将会返回一个对象, 该对象要注册为Spring应用上下文中的bean。 方法体中包含了最终产生bean实例的逻辑。默认情况下, bean的ID与带有 @Bean注解的方法名是一样的(compactDisc)。可以通过name属性指定一个不同的名字:@Bean public CompactDisc compactDisc() { return new SgtPeppers(); }
借助JavaConfig实现注入@Bean(name="name1") public CompactDisc compactDisc() { return new SgtPeppers(); }
此时spring容器中已经存在CompactDisc Bean,可以根据compactDisc()方法将其注入到CDPlayer中:@Bean public CompactDisc compactDisc() { return new SgtPeppers(); }
也可以将spring容器中存在的任意CompactDisc Bean注入到CDPlayer中:@Bean public CDPlayer cdPlayer() { return new CDPlayer(compactDisc()); }
@Bean public CDPlayer cdPlayer(CompactDisc compactDisc) { return new CDPlayer(compactDisc); }
三、自动化装配bean
spring从两个角度来实现自动化装配:
- 组件扫描(component scanning) : Spring会自动发现应用上下文中所创建的bean。
- 自动装配(autowiring) : Spring自动满足bean之间的依赖。
- 创建可被发现的bean
public interface CompactDisc {
void play();
}
@Component
public class SgtPeppers implements CompactDisc {
...
}
spring根据类名为SgtPeppersbean设置一个ID为sgtPeppers(将类名的第一个字母变为小写)。如果想为这个bean设置不同的ID:
@Component("name")
public class SgtPeppers implements CompactDisc {
...
}
这就将这个bean的ID标记为了name。
- 通过为bean添加注解实现自动装配
简单来说, 自动装配就是让Spring自动满足bean依赖的一种方法, 在满足依赖的过程中, 会在Spring应用上下文中寻找匹配某个bean需求的其他bean。 为了声明要进行自动装配, 我们可以借助Spring的@Autowired注解。
@Component
public class CDPlayer implements MediaPlayer {
private CompactDisc cd;
public CDPlayer() {
}
@Autowired
public CDPlayer(CompactDisc cd) {
this.cd = cd;
}
public void play() {
cd.play();
}
}
@Autowired注解不仅能够用在构造器上, 还能用在属性的Setter方法上。 比如说, 如果CDPlayer有一个setCompactDisc()方法, 那么可以采用如下的注解形式进行自动装配:
@Autowired
public void setCompactDisc(CompactDisc cd) {
this.cd = cd;
}
实际上, Setter方法并没有什么特殊之处。 @Autowired注解可以用在类的任何方法上。
在自动装配中, Spring同时支持@Inject和@Autowired。 尽管@Inject和@Autowired之间有着一些细微的差别, 但是在大多数场景下, 它们都是可以互相替换的。
- 设置组件扫描
- 通过Java代码
//如果没有其他配置的话, @ComponentScan默认会扫描与配置类相同的包。
@Configuration
@ComponentScan
public class CDPlayerConfig {
}
//可以指定包
@Configuration
@ComponentScan("soundsystem")
public class CDPlayerConfig {
}
- 使用XML
<context:component-scan base-package="packagename" />
四、混合配置
- 两个java配置类混合
@Configuration @Import(CDPlayerConfig.class,CDConfig.class) public class SoundSystemConfig {}
- 一个java配置类与xml中配置的bean混合
@Configuration @Import(CDPlayerConfig.class) @ImportResource("classpath:cd-config.xml") public class SoundSystemConfig {}
- 以上两种方式都是采用java类配置的,还可以在xml中混合配置:
<bean class="soundsystem.CDConfig" /> <import resource="cdplayer-config.xml" />