Spring声明Bean

创建应用对象之间协作关系的行为通常被称为装配,这也是Spring依赖注入的本质。

Spring容器

Spring有两个很接口:BeanFactory和ApplicationContext接口,它们都可代表Spring容器,Spring容器是生成Bean实例的工厂,并管理容器中的Bean。

声明Bean

创建Spring配置

Spring是一个基于容器的框架,如果没有配置Spring,那它就是一个空容器,对于我们也就毫无用处。因此,我们需要配置Spring来告诉容器需要加载哪些Bean和如何装配这些Bean。

Spring容器提供了两种装配Bean的方式:

  1. 使用一个或多个XML文件作为配置文件
  2. 基于Java注解进行配置 使用XML文件声明bean时,Spring配置文件的根元素来源于spring beans命令空间所定义的元素。在元素内,可以放置所有的Spring配置元素。
    下面是一个典型的Spring XML配置文件:
1
2
3
4
5
6
7
<?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-3.0.xsd">

</beans>

但是不是唯一的Soring命名空间,Spring的核心框架自带了10个明明空间配置。

命名空间 用途
aop 为声明切面以及将@AspectJ注解的类代理为Spring切面提供了配置元素
beans 支持声明bean和装配bean,是Spring最核心也是最原始的命名空间
context 为配置Spring上下文提供了配置元素,包括自动检测和自动装配Bean、注入非Spring直接管理的对象
jee 提供了与Java EE API的集成,例如JNDI、EJB
jms 为声明消息驱动的POJO提供了配置元素
lang 支持配置由Groovy、JRuby或BeanShell等脚本实现的Bean
mvc 启用Spring MVC的能力
oxm 支持Spring对象到XML映射配置
tx 提供声明式事务配置
util 提供各种各样的工具类元素,包括把集合配置为Bean、支持属性占位符元素

除了Spring框架自带的命名空间,Spring Portfolio的许多成员也提供了它们自己的Spring命名空间配置。

声明一个简单的Bean

声明一个杂技师类Juggler,代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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() throws PerformanceException {
System.out.println("JUGGLING " + beanBags + " BEANBAGS");
}
}

Juggler类默认可以同时抛3个豆袋子,但是也可以通过构造器设置豆袋子的个数。

声明一个bean:

1
<bean id="duke" class="com.springinaction.springidol.Juggler" />

元素是Spring中最基本的配置单元。当Spring容器加载该bean时,Spring默认使用构造器类实例化duke Bean。
深层次来说,配置文件中的 默认以反射方式来调用该类无参数的构造器。
Spring框架解析上面的元素可以得到两个字符串:其中idStr=”duke”,classStr=”com.springinaction.springidol.Juggler”。
Spring底层会执行形如一下格式的代码:

1
2
3
4
5
6
String idStr = ...;
String classStr = ...;

Class clazz = Class.forName(classStr);
Object obj = clazz.newInstance();
container.put(idStr, obj);// container代表Spring容器

上面是最基本的反射代码,在Spring底层中,代码会更完善一些。

实际上,duke会使用如下代码来创建:

1
new com.springinaction.springidol.Juggler();

为了给duke一个排练机会,可以使用如下代码加载spring上下文:

1
2
3
4
ApplicationContext ctx = new ClassPathXmlApplicationContext("spring-idol.xml");

Performer performer = (Performer)ctx.getBean("duke");
performer.perform();

为了能让评委心动,duke决定打破世界纪录:同时抛15个豆袋子。下面我们使用带参数的构造方法来设置个数。

构造器注入

1
2
3
<bean id="duke" class="com.springinaction.springidol.Juggler">
<constructor-arg value="15" />
</bean>

在构造Bean的时候,我们使用元素告诉Spring额外的信息。

注入对象引用

我们不能使用的ref属性为第二个构造函数赋值,因为我们将要出入的是对象。这里我们使用ref属性来指向要注入bean的id。
此时Spring将会执行如下的代码:

1
2
3
4
5
6
Stirng idStr = ...;
String refStr = ...;
Object paramBean = constainer.get(refStr);
Object obj = new xxx(paramBean);// xxx为bean的包名+类名
// constainer代表Spring容器
constainer.put(idStr, obj);

通过工厂方法创建Bean

有时候静态工厂方法是实例化对象的唯一方法,spring支持通过元素的factory-method属性来装配工厂创建的bean。一般来说,单例类的实例只能通过静态工厂方法来创建。
Stage类是一个典型的单例类:

1
2
3
4
5
6
7
8
9
10
11
12
13
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上下文中将Stage配置为bean,可以像下面的配置来使用factory-method:

1
2
<bean id="theStage" class="com.springinaction.springidol.Stage"
factory-method="getInstance" />

Bean的作用域

Spring的bean作用域允许用户配置所创建的Bean属于哪一种作用域,而无需在Bean的实现里硬编码作用域规则。

作用域 定义
singleton 在每一个spring容器中,一个bean定义只有一个对象实例(默认
prototype 允许bean的定义被实例化任意次(每次调用豆创建一个实例)
request 在一次HTTP请求中,每个bean定义对应一个实例。该作用域仅在基于web的spring上下文(例如spring mvc)中才有效
session 在一个HTTP Session中,每个bean对应一个实例。该作用域仅在基于web的spring上下文(例如spring mvc)中才有效
global-session 在一个全局HTTP Session中,每个bean定义一个实例。该作用域仅在Protlet上下文中才有效。

注意:spring有关单例的概念限于spring上下文的范围内,不像真正的单例,在每个类加载器中保证只有一个实例。spring的单例只能保证在每个应用上下文中只有一个bean的实例。没有人能够阻止你使用传统的方式实话同一个bean,甚至你可以定义几个声明来实例化同一个Bean。

初始化和销毁Bean

为满足初始化和销毁Bean的需求,Spring提供了Bean的声明周期的钩子方法。为bean定义初始化和销毁操作,只需要使用init-methoddestroy-method参数来配置bean元素,init-method属性指定了在初始化bean时要调用的方法,类似的,destroy-method属性指定了bean从容器移除之前要调用的方法。

分享到