创建应用对象之间关联关系的传统方法(通过构造器或者查找)通常会导致结构复杂的代码,这些代码很难被复用,也很难进行单元测试。
在Spring中,对象无需自己负责查找或创建与其关联的其他对象。相反,容器负责把需要相互协作的对象引用赋予各个对象。
创建应用对象之间协作关系的行为通常被称为装配,这也是依赖注入的本质。
1.创建Spring配置
(1)传统上,Spring使用一个或多个XML文件作为配置文件,而Spring3.0还同时提供了基于Java注解的配置方式。
(2)Spring配置文件的根元素是来源于Spring beans命名空间所定义<beans>
元素。
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>3.0.0.RELEASE</version>
<scope>runtime</scope>
</dependency>
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="..." class="...">
<!-- collaborators and configuration for this bean go here -->
</bean>
<bean id="..." class="...">
<!-- collaborators and configuration for this bean go here -->
</bean>
<!-- more bean definitions go here -->
</beans>
2.声明一个简单Bean
Performer接口
package com.springinaction.springidol;
public interface Performer
{
void perform();
}
Juggler Bean
package com.springinaction.springidol;
public class Juggler implements Performer
{
private int beanBags = 3;
public Juggler()
{
}
public Juggler(int beanBags)
{
this.beanBags = beanBags;
}
public void perform()
{
System.out.println("JUGGLER " + beanBags + " BEANBAGS");
}
}
spring-idol.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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="duke" class="com.springinaction.springidol.Juggler" />
</beans>
加载Spring上下文(当Spring容器加载该Bean时,Spring将使用默认的构造器来实例化duke Bean)
ApplicationContext ctx = new ClassPathXmlApplicationContext(
"com/springinaction/springidol/spring-idol.xml");
Performer performer = (Performer)ctx.getBean("duke");
performer.perform();
3.通过构造器注入
<bean id="duke" class="com.springinaction.springidol.Juggler">
<constructor-arg value="15" />
</bean>
通过构造器注入对象引用
Poem接口
package com.springinaction.springidol;
public interface Poem
{
void recite();
}
package com.springinaction.springidol;
public class Sonnet29 implements Poem
{
private static String[] LINES = {"Don't aim for success if you really want it,",
"just stick to what you love and believe in,", "and it will come naturally."};
public Sonnet29()
{
}
public void recite()
{
for (int i = 0; i < LINES.length; i++ )
{
System.out.println(LINES[i]);
}
}
}
会朗诵诗歌的杂技师
package com.springinaction.springidol;
public class PoeticJuggler extends Juggler
{
private Poem poem;
public PoeticJuggler(Poem poem)
{
super();
this.poem = poem;
}
public PoeticJuggler(int beanBags, Poem poem)
{
super(beanBags);
this.poem = poem;
}
public void perform()
{
super.perform();
System.out.println("While reciting...");
poem.recite();
}
}
spring-idol.xml
<bean id="sonnet29" class="com.springinaction.springidol.Sonnet29" />
<bean id="poeticDuke" class="com.springinaction.springidol.PoeticJuggler">
<constructor-arg value="15" />
<constructor-arg ref="sonnet29" />
</bean>
通过工厂方法创建Bean
要装配的对象需要通过静态方法来创建(单例类)
package com.springinaction.springidol;
public class Stage
{
private Stage()
{
}
private static class StageSingletonHolder
{
static Stage instance = new Stage();
}
public static Stage getInstance()
{
return StageSingletonHolder.instance;
}
}
spring-idol.xml
<bean id="theStage" class="com.springinaction.springidol.Stage"
factory-method="getInstance" />
4.Bean的作用域
所有的Spring Bean默认都是单例。
为了让Spring在每次请求时都为Bean产生一个新的实例,我们只需要配置Bean的scope属性为prototype即可。
作用域 | 定义 |
---|---|
singleton | 在每一个Spring容器中,一个Bean定义只有一个对象实例(默认) |
prototype | 允许Bean的定义可以被实例化任意次(每次调用都创建一个实例) |
request | 在一次HTTP请求中,每个Bean定义对应一个实例。该作用域仅在基于Web的Spring上下文中才有效 |
session | 在一个HTTP Session中,每个Bean定义对应一个实例。该作用域仅在基于Web的Spring上下文中才有效 |
global-session | 在一个全局HTTP Session中,每个Bean定义对应一个实例。该作用域仅在Portlet上下文中才有效 |
Spring的单例Bean只能保证在每个应用上下文中只有一个Bean的实例。没有人可以阻止你使用传统的方式实例化同一个Bean,或者你甚至可以定义几个<bean>
声明来实例化同一个Bean。
5.初始化和销毁Bean
为Bean定义初始化和销毁操作,只需要使用init-method和destroy-method参数来配置<bean>
元素。init-method属性指定了在初始化Bean时要调用的方法。类似的,destroy-method属性指定了Bean从容器移除之前要调用的方法。
package com.springinaction.springidol;
public class Auditorium
{
public void turnOnLights()
{
// ...
}
public void turnOffLights()
{
// ...
}
}
<bean id="auditorium" class="com.springinaction.springidol.Auditorium"
init-method="turnOnLights" destroy-method="turnOffLights" />
为Bean定义初始化和销毁方法的另一种可选方式是,让Bean实现Spring的InitializingBean和DisposableBean接口。Spring容器以特殊的方式对待实现这两个接口的Bean,允许它们进入Bean的生命周期。InitializingBean声明了一个afterPropertiesSet()方法作为初始化方法。而DisposableBean声明了一个destroy()方法,该方法在Bean从应用上下文移除时会被调用。使用这些生命周期接口的最大好处就是Spring能够自动检测实现了这些接口的Bean,而无需额外的配置。实现这些接口的缺点是Bean与Spring的API产生了耦合。
package com.springinaction.springidol;
import org.springframework.beans.factory.InitializingBean;
public class Auditoriums implements InitializingBean
{
public void afterPropertiesSet()
throws Exception
{
// ...
}
}
<bean id="auditoriums" class="com.springinaction.springidol.Auditoriums" />
default-init-method属性为应用上下文中所有的Bean设置了共同的初始化方法。 default-destroy-method属性为应用上下文中所有的Bean设置了共同的销毁方法。
spring-idol.xml
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd"
default-init-method="turnOnLights" default-destroy-method="turnOffLights">
<bean id="auditoriumss" class="com.springinaction.springidol.Auditoriumss" />
package com.springinaction.springidol;
public class Auditoriumss
{
public void turnOnLights()
{
// ...
}
}
test result
@Test
public void test4()
{
ApplicationContext ctx = new ClassPathXmlApplicationContext(
"com/springinaction/springidol/spring-idol.xml");
}
------------------------------
Auditorium turn on lights.
Auditoriums initial.
Auditoriumss turn on lights.