创建应用对象之间协作关系的行为通常被称为装配,这也是Spring依赖注入的本质。
Spring容器
Spring有两个很接口:BeanFactory和ApplicationContext接口,它们都可代表Spring容器,Spring容器是生成Bean实例的工厂,并管理容器中的Bean。
声明Bean
创建Spring配置
Spring是一个基于容器的框架,如果没有配置Spring,那它就是一个空容器,对于我们也就毫无用处。因此,我们需要配置Spring来告诉容器需要加载哪些Bean和如何装配这些Bean。
Spring容器提供了两种装配Bean的方式:
- 使用一个或多个XML文件作为配置文件
- 基于Java注解进行配置
使用XML文件声明bean时,Spring配置文件的根元素来源于spring beans命令空间所定义的
元素。在 元素内,可以放置所有的Spring配置元素。
下面是一个典型的Spring XML配置文件:
1 | <?xml version="1.0" encoding="UTF-8"?> |
但是
| 命名空间 | 用途 |
|---|---|
| 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
19package 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底层会执行形如一下格式的代码:1
2
3
4
5
6String 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 | ApplicationContext ctx = new ClassPathXmlApplicationContext("spring-idol.xml"); |
为了能让评委心动,duke决定打破世界纪录:同时抛15个豆袋子。下面我们使用带参数的构造方法来设置个数。
构造器注入
1 | <bean id="duke" class="com.springinaction.springidol.Juggler"> |
在构造Bean的时候,我们使用
注入对象引用
我们不能使用
此时Spring将会执行如下的代码:
1 | Stirng idStr = ...; |
通过工厂方法创建Bean
有时候静态工厂方法是实例化对象的唯一方法,spring支持通过
Stage类是一个典型的单例类:
1 | package com.springinaction.springidol; |
为了在spring上下文中将Stage配置为bean,可以像下面的配置来使用factory-method:
1 | <bean id="theStage" class="com.springinaction.springidol.Stage" |
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的需求,Spring提供了Bean的声明周期的钩子方法。为bean定义初始化和销毁操作,只需要使用init-method和destroy-method参数来配置bean元素,init-method属性指定了在初始化bean时要调用的方法,类似的,destroy-method属性指定了bean从容器移除之前要调用的方法。
