一. 装配Bean介绍
创建应用对象之间协作关系的行为通常称为装配(wiring)
三种装配机制:
- 在XML中进行显式配置
- 在Java中进行显式配置
- 隐式的bean发现机制和自动装配
二. 自动化装配bean
Spring从两个角度来实现自动化装配:
- 组件扫描: Spring会自动发现应用上下文中所创建的bean
- 自动装配: Spring自动满足bean之间的依赖
自动化装配步骤: ①启用组件扫描, ②为bean添加注解实现自动化装配
①启用组件扫描:
- Java显式配置启动组件扫描
- XML显示配置启动组件扫描
Java显式配置
package soundsystem;
import org.springframework.context.annotation.compoentScan;
import org.springframework.context.annotation.Configuration;
@Configuration
@ComponentScan
public class CDPlayerConfig {
}
使用@ComponentScan注解, 启动组件扫描. @ComponentScan默认扫描与配置类相同的包, 查找带有@Component注解的类, 发现后会自动为该类创建一个bean.
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:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
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
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd">
<context: component-scan base-package="soundsystem" />
</beans>
②声明bean, 设置扫描的基本包
声明bean:
声明bean组件用@Component
@Component 注解在类上, 表明该类会作为组件类, 并告知Spring要为这个类创建bean
Spring支持将@Named作为@Component注解的替代方案.在大多数场景,两者是可以互相替换的.一般用@Component
为组件扫描的bean命名:
默认ID是类名第一个字母变小写. 自己命名则用: @Component("yourName")
设置组件扫描的基本包:
默认以配置类所在的包作为基础包(base package)来扫描组件
明确设置基础包,用basePackages属性:
设置一个基础包
@Configuration
@ComponentScan(basePackages="soundsystem")
public class CDPlayerConfig { }
设置多个基础包:
@Configuration
@ComponentScan(basePackages={"soundsystem", "video"})
public class CDPlayerConfig { }
上面属性都是用的String类型表示, 这是类型不安全(not type-safe), 如果重构代码可能出错
除了将包设置为String类型外,还可以将其指定为包中所包含的类或接口
@Configuration
@ComponentScan(basePackageClasses={CDPlayer.class, DVDPlayer.class})
public class CDPlayerConfig { }
③为bean添加注解实现自动装配:
自动装配就是让Spring自动满足bean依赖的一种方法, 在满足依赖的过程中, 会在Spring应用上下文中寻找匹配某个bean需求的其他bean.用@Autowired来注解要自动装配的bean,
@Autowired使用:
@Autowired注解在有参构造器上, 表明当Spring创建该类 bean时, 会通过这个构造器来进行实例化,并且会传入一个可设置给该构造器参数类型的bean
@Autowired注解在Setter方法上
@Autowired注解在类的任何方法上, 不管是构造器, Setter方法还是其他的方法, Spring都会尝试满足方法参数上所声明的依赖.Ⅰ如果有且只有一个bean匹配依赖需求的话, 那么这个bean将会被装配进来. Ⅱ如果没有匹配的bean, 那么在应用上下文创建的时候, Spring会抛出一个异常. Ⅲ如果有多个bean都能满足依赖关系的话, Spring将抛出异常, 表明没有明确指定要选择哪个bean进行装配.
在大多数场景下,@Inject和@Autowired可以相互替换, 一般两个都可以用
三. Java代码装配bean (JavaConfig)
①创建JavaConfig类
创建JavaConfig类的关键在于为其添加@Configuration注解. @Configuration注解表明这个类是一个配置类, 该类应该包含在Spring上下文中如何创建bean的细节.
例:
package soundsystem;
import org.springframework.context.annotation.Configuration;
@Configuration
public class CDPlayerConfig { }
这个CDPlayerConfig就是一个JavaConfig类, 使用了@Configuration. 因为这里要用JavaConfig所以不用@ComponentScan注解
②声明简单的bean
在JavaConfig中声明bean, 需要编写一个方法, 这个方法会创建所需类型的实例, 然后给这个方法添加@Bean注解.
例: 声明一个bean
@Bean
public CompactDisc sgtPeppers() {
return new SgtPeppers();
}
@Bean注解会告诉Spring这个方法将会返回一个对象, 该对象要注册为Spring应用上下文中的bean.方法体中包含了最终产生bean实例的逻辑.
默认情况下, bean的ID与带有@Bean注解的方法名是一样的.如果想用不同的名字,可以用name属性重命名该方法.
方法只要能返回一个实例即可,无论是用构造器, Setter方法还是其他Java代码, 只要能产生bean实例都可以.
③JavaConfig配置实现注入
上面声明的简单bean中, 没有其他依赖. 下面声明一个CDplayer bean, 它依赖于CompactDisc(方法sgtPeppers()返回CompactDisc类型实例).
@Bean
public CDPlayer cdPlayer() {
return new CDPlayer(sgtPeppers());
}
方法cdPlayer()和sgtPeppers()都是使用@Bean注解, 表明这个方法会创建一个bean实例并将其注册到Spring应用上下文中. 所创建的bean ID默认与方法的名字相同.
但是cdPlayer()和sgtPeppers()实例化方式不同, sgtPappers()使用默认的构造器构建实例. 而cdPlayer()是调用了需要传入CompactDisc对象的构造器来创建CDPlayer实例.
看起来, CompactDisc是通过调用sgtPeppers()得到的, 但情况并非完全如此.因为sgtPeppers()方法上添加了@Bean注解, Spring将会拦截所有对它的调用. 并确保直接返回该方法所创建的bean, 而不是每次都对其进行实际的调用.
例如要创建两个bean
@Bean
public CDPlayer cdPlayer() {
return new CDPlayer(sgtPeppers());
}
@Bean
public CDPlayer anotherCDPlayer() {
return new CDPlayer(sgtPeppers());
}
上面创建两个同一个依赖(sgtPeppers())的bean, 如果对sgtPeppers()调用像其他Java方法调用一样的话, 那么每个CDPlayer实例都会有一个自己特有的CompactDisc实例.但实际上, 一个CompactDisc实例就够了. 我们可以将同一个CompactDisc实例注入到任意数量的其他bean之中. 默认情况下, Spring中bean都是单例的.所以, Spring会拦截对sgtPeppers()的调用并确保返回的是Spring所创建的bean.因此上面两个bean会得到相同的CompactDisc实例.
除了通过调用方法来引用bean, 还可以将依赖作为参数来引用bean
@Bean
public CDplayer cdPlayer(CompactDisc compactDisc) {
return new CDPlayer(compactDisc);
}
带有@Bean注解的方法可以采用任何必要的Java功能来产生bean实例
四. XML装配bean
1. 创建XML配置规范
在使用XML为Spring装配bean之前, 需要创建一个新的配置规范.
Spring XML 基本配置:
<?xml version="1.0" encoding="UTF-8"?>
<!-- Application context definition. -->
<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:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx" xmlns:jdbc="http://www.springframework.org/schema/jdbc" xmlns:aop="http://www.springframework.org/schema/aop"
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
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/jdbc
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/jdbc/spring-jdbc.xsd"
default-autowire="byName">
<!-- configuration details go here -->
</beans>
2. 声明一个简单的<bean>
例如声明一个CompactDisc bean:
<bean class="soundsystem.SgtPeppers" />
创建这个bean的类是通过class属性来指定的, 并且要使用全限定的类名.
因为没有明确给定ID, 所以这个bean将会根据全限定类名来进行命名. 在本例中, bean的ID将会是"soundsystem.SgtPeppers#0".如果声明了另一个SgtPeppers, 并且没有明确进行标识, 那么它自动得到的ID将会是"soundsystem.SgtPeppers#1".
使用id属性, 为每一个bean设置名字
<bean id="compactDisc" class="soundsystem.SgtPeppers" />
当Spring发现这个<bean>元素时, 它将会调用SgtPeppers的默认构造器来创建bean.
3. 借助构造器注入初始化bean
在Spring XML配置中, 声明bean只有一种方式,但是声明DI有多种可选的配置方案和风格.
构造器注入配置方案:
- <constructor-arg> 元素
- 使用Spring3.0 所引入的c-命名空间
①构造器注入bean引用
下面将SgtPeppers bean注入到CDPlayer bean中.
<bean id="cdPlayer" class="soundsystem.CDPlayer">
<constructor-arg ref="compactDisc">
</bean>
<constructor-arg>元素告知Spring要将一个ID为compactDisc的bean引用传递到CDPlayer的构造器中.
在使用c-命名空间时,先在XML顶部文件声明添加一个模式:
xmlns:c="http://www.springframework.org/schema/c"
使用c-命名空间完成相同功能:
<bean id="cdPlayer" class="soundsystem.CDPlayer"
c:cd-ref="compactDisc" />
上面这种方式调试无法执行
替代方案:
<bean id="cdPlayer" class="soundsystem.CDPlayer"
c:_0-ref="compactDisc" />
②将字面量注入到构造器中
使用value属性
<constructor-arg value="The Beatles" />
使用c-命名空间有两种方法, 一是引用构造器参数的名字
<bean id="teacher"
class="school.person"
c:_id="001"
c:_name="Tom" />
另一种是通过参数索引装配相同的字面量值
<bean id="teacher"
class="school.person"
c:_0="001"
c:_1="Tom" />
③装配集合
使用<constructor-arg>的 <list>或<set>子元素. c-命名空间无法装配集合
使用<list>元素
<constructor-arg>
<value>Tom</value>
<value>Jack</value>
<value>Mikes</value>
</constructor-arg>
类似的可以使用<ref>元素代替<value>
使用<set>元素与上相似, 但使用<set>时, 所有的重复的值都会被忽略掉,存放顺序也不保证.
4. 设置属性
上面的类都是通过构造器注入的, 没有使用属性的Setter方法. 接下来为如何受用Spring XML实现属性注入.
使用规则: 强依赖使用构造器注入, 可选依赖使用属性注入
<bean id="cdPlayer"
class="soundsystem.CDPlayer">
<property name="compactDisc" ref="compactDisc" />
</bean>
下面使用p-命名空间
添加模式
xmlns:p="http://www.springframework.org/schema/p"
使用p-命名空间完成上面功能
<bean id="cdPlayer"
class="soundsystem.CDPlayer"
p:compactDisc-ref="compactDisc" />
装配字面值
<bean id="customer" class="shop.customerbook">
<property name="id" value="001" />
<property name="books" >
<list>
<value>the name</value>
<value>bule sky</value>
<value>come on</value>
</list>
</property>
</bean>
使用p-命名空间完成上面功能
<bean id="customer" class="shop.customerbook"
p:id="001">
<property name="books" >
<list>
<value>the name</value>
<value>bule sky</value>
<value>come on</value>
</list>
</property>
</bean>
p-命名空间虽然不能装配集合,但是util-命名空间可以装配集合
添加模式
xmlns:util="http://www.springframework.org/schema/util"
<util:list id="book">
<value>the name</value>
<value>bule sky</value>
<value>come on</value>
</util:list>
<bean id="customer" class="shop.customerbook"
p:id="001"
p:book-ref="book" />
util-命名空间还有set, map, properties等其他元素.
五. 导入和混合配置
1. 在JavaConfig中引入XML配置
2. 在XML配置中引用JavaConfig