Spring
总共有十几个组件,但是真正核心的组件只有三个:Core
、Context
和Bean
。它们构建起了整个Spring
的骨骼架构,没有它们就不可能有AOP
、Web
等上层的特性功能。
# 一、Spring
的设计理念
Bean
组件是Spring
核心中的重点,Spring
就是面向Bean
编程的[Bean Oriented Programming:BOP
]就像Object
对OOP
的意义一样,没有对象的概念就像没有面向对象的编程,在Spring
中没有Bean
也就没有Spring
存在的意义。我们使用Spring
的主要一个原因就是Spring
会把对象之间的依赖关系转而用配置文件来管理。也就是依赖注入机制。而这个注入关系在一个叫IOC
的容器中管理,而IOC
容器就是被Bean
包裹的对象。Spring
正是通过把对象包装在Bean
中从而达到管理这些对象及做一系列额外操作的目的。
前面如果把Bean
比作一场演出中的演员,Context
就是这场演出的舞台背景,而Core
应该就是演出的道具了。Bean
包装的是Object
,而Object
必然有数据,如何给这些数据提供生存环境就是Context
要解决的问题,对Context
来说它就是要发现每个Bean
之间的关系并维护好这种关系。所以Context
就是一个Bean
关系的集合,这种关系集合又叫IOC
容器。Core
组件用来发现、建立和维护每个Bean
之间所需的一系列工具,把Core
组件也可以看成是Util
。

# 二、Bean
组件
Bean
组件在Spring
的org.springframework.beans
包下,在这个包下的所有类主要解决了3件事:Bean
的定义、Bean
的创建及对Bean
的解析。对Spring
使用者来说唯一需要关心的就是Bean
的创建,其他两个由Spring
在内部完成。BeanDefination
:Bean
的定义完整的描述了在Spring
配置文件中定义的<bean/>
节点中所有的信息,包括各种子节点。当Spring
成功解析<bean/>
节点后,在Spring
内部它就被转化成BeanDefinition
对象,以后所有操作都是对这个对象操作。
Bean的解析过程非常复杂,功能被分的很细。因为这里需要被扩展的地方很多,必须保证有足够的灵活性,以应对可能的变化。Bean
的解析主要就是对Spring配置文件的解析。
# 三、Context
组件
Context
在Spring
的org.springframework.context
包下,给Spring
提供一个运行时的环境,用于保存各个对象的状态。ApplicationContext
是Context
的父类,它除了能标识一个应用环境的基本信息外,还集成了5个接口来扩展Context
的功能。例如:通过继承 BeanFactory 表明容器中运行的主体对象是Bean
,另外继承了ResourceLoader
接口,使得ApplicationContext
可以访问外部资源(在Core
中说明);
【1】ApplicationContext
的子类主要包含两个方面:
● ConfigurableApplicationContext
表示该Context
是可修改的,也就是在构建Context
中,用户可以动态添加或修改已有的配置信息,其中最经常使用的是可更新的Context
,即AbstractRefreshableApplicationContext
类;
● WebApplicationContext
为Web
装备的Context
,可直接访问ServletContext
;
【2】再往下分别就是构建Context
的文件类型,接着就是访问Context
的方式,这样一级一级构成了完成的Context
等级层次。总体来说 ApplicationContext
必须要完成一下几件事情:
✔ 标识一个应用环境;
✔ 利用BeanFactory
创建Bean
对象;
✔ 保存对象关系表;
✔ 能够捕捉各种事件;
Context 作为Spring
的IOC容器,基本上整合了Spring
的大部分功能,或者说是大部分功能的基础。
# 四、Core
组件
Core
组件作为Spring
的核心组件,其中包含了很多关键类,例如:定义了资源的访问方式。这种将所有资源都抽象成一个接口的方式很值得以后的设计中拿来学习。
Context
与Core
之间的关系:比如Context
一般会把资源的加载、解析和描述工作委托给ResourcePatternResolver
类来完成,它相当于一个接头人,把资源的加载、解析和资源的定义整合在一起便于其他组件使用,在Core
组件中还有很多类似的方式。
# 五、IOC
容器如何工作
IOC
容器实际上是Context
组件结合其他两个组件共同构建了一个Bean
关系网,如何构建这个关系网,构建的入口就在AbstractApplicationContext
类的 refresh
方法中,这个方法代码如下:链接 (opens new window)
@Override
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// 为刷新做准备的 Context
prepareRefresh();
// 刷新所有BeanFactory子容器
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// 创建BeanFactory
prepareBeanFactory(beanFactory);
try {
// 注册实现了BeanPostProcess接口的Bean
postProcessBeanFactory(beanFactory);
// 初始化和执行BeanFactoryPostProcess beans
invokeBeanFactoryPostProcessors(beanFactory);
// 初始化和执行BeanPostProcess beans
registerBeanPostProcessors(beanFactory);
// 初始化 message source
initMessageSource();
// 初始化 event multicaster
initApplicationEventMulticaster();
// 刷新子类实现的方法
onRefresh();
// 检查注册事件
registerListeners();
// 初始化 (non-lazy-init) 单例Bean
finishBeanFactoryInitialization(beanFactory);
// 执行LifecycleProcessor.onRefresh()和ContextRefreshedEvent事件
finishRefresh();
}
catch (BeansException ex) {
destroyBeans();//如果刷新失败那么就会将已经创建好的单例Bean销毁掉
cancelRefresh(ex);//重置context的活动状态
throw ex;//抛出异常
}
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
这个方法就是构建整个IOC
容器过程的完整代码,了解里面的每一行代码,基本上就了解了大部分Spring
的原理和功能。这段主要包含一下步骤:
1)、构建BeanFactory
,以便于产生所需的“演员”;
2)、注册可能感兴趣的事件;
3)、创建Bean
实例对象;
4)、触发被监听的事件;
首先创建和配置BeanFactory
《容器》,这里是refresh
,也就是刷新配置。前面介绍了Context
有可更新的子类,这里正是实现这个功能,当BeanFactory
存在时就更新,如果不存在就新创建。更新BeanFactory
的方法如下:
@Override
protected final void refreshBeanFactory() throws BeansException {
if (hasBeanFactory()) {//如果已经存在一个bean工厂那么就将其销毁,关闭。
destroyBeans();
closeBeanFactory();
}
try {
DefaultListableBeanFactory beanFactory = createBeanFactory();//新建一个Bean工厂。
beanFactory.setSerializationId(getId());
customizeBeanFactory(beanFactory);//自定义bean工厂。
loadBeanDefinitions(beanFactory);//加载BeanDefinition
synchronized (this.beanFactoryMonitor) {
this.beanFactory = beanFactory;//将创建好的bean工厂的引用交给的context来管理。
}
}
catch (IOException ex) {//加载bean定义资源的时候可能会抛出异常。
throw new ApplicationContextException("I/O error parsing bean definition source for "
+ getDisplayName(), ex);
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
这个方法实现了AbstractApplictionContext
的抽象方法refreshBeanFactory
,这段代码清楚的说明了BeanFactory
的创建过程。注意BeanFactory
对象的类型变化,BeanFactory
有很多子类,在什么情况下使用非常关键。BeanFactory
的原始对象是DefaultListableBeanFactory
,这个非常关键,因为它涉及后面对这个对象的多种操作,下面看一下这个类的继承关系图:

从上图可以发现除了BeanFactory
相关类外,还发现与Bean
的register
相关的类。这在refreshBeanFactory
方法的loadBeanDefinitions(beanFactory)
一行将找到答案,这个方法将加载、解析Bean
的定义,也就是把用户定义的数据结构转化为IOC
容器中的特定数据结构。
创建好BeanFactory
后,添加一些Spring
本身需要的工具类,这个操作在AbstractApplictionContext
的prepareBeanFactory
的prepareBeanFactory
方法中完成。
在AbstractApplicationContext
中接下来的3行代码Spring
的功能扩展性能起了至关重要的作用。前两行主要是让你现在可以对已经构建的BeanFactory
的配置做修改,后面一行就是让你可以对以后再创建 Bean的实例对象时添加一些自定义的操作。所以它们都扩展了Spring
的功能,要学习Spring
必须搞清楚这一部分。
其中在 invokeBeanFactoryPostProcessors
方法中主要是获取实现BeanFactoryPostProcess
接口的子类,并执行它的postProcessBeanFactory
方法,这个方法的声明如下:
void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException
它的参数是beanFactory
,说明可以对beanFactory
做修改,beanFactory
是ConfigurableListableBeanFactory
类型的,这也印证了前面介绍的不同BeanFactory
所使用的场合不同,这里只能是可配置的BeanFactory
,防止一些数据被用户随意修改。
registerBeanPostProcess
方法也可以获取用户定义的实现了BeanPostProcessor
接口的子类,并把他们注册到BeanFacotry
对象中的beanPostProcessor
变量中。在BeanPostProcessor
中声明了两个方法:postProcessBeforeInitialization
和postProcessAfterInitialization
,分别用于Bean
对象初始化时执行,可以执行用户自定义的操作。后面几行代码是初始化监听事件和对系统的其他监听者的注册,监听者必须是 ApplicationListener
的子类。
protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
//不使用TempClassLoader
beanFactory.setTempClassLoader(null);
//禁止修改当前Bean的配置信息
beanFactory.freezeConfiguration();
//实例化non-lazy-init类型的bean
beanFactory.preInstantiateSingletons();
}
2
3
4
5
6
7
8
从上面的代码中可以发现Bean
的实例化是在BeanFactory
中发生的。PreInstantiateSingletons
方法的代码如下:
@Override
public void preInstantiateSingletons() throws BeansException {
if (this.logger.isDebugEnabled()) { //日志(这是一种好的日志处理方式,当没有开启debug级别时,就会省下一次字符串拼接),spring源码里到处都是这样的处理,可以学习。
this.logger.debug("Pre-instantiating singletons in " + this);
}
// Iterate over a copy to allow for init methods which in turn register new bean definitions.
// While this may not be part of the regular factory bootstrap, it does otherwise work fine.
//拷贝一个新的list ,this.beanDefinitionNames 干嘛的,上文大概已有说明,可以结合《Spring 源码阅读 BeanFactory(二) 之registerBeanDefinition方法》一块看
List<String> beanNames = new ArrayList<String>(this.beanDefinitionNames);
// Trigger initialization of all non-lazy singleton beans...
for (String beanName : beanNames) { //遍历beanName
//这里先解释一下getMergedLocalBeanDefinition方法的含义,因为这个方法会常常看到。Bean定义公共的抽象类是AbstractBeanDefinition,普通的Bean在Spring加载Bean定义的时候,实例化出来的是GenericBeanDefinition,而Spring上下文包括实例化所有Bean用的AbstractBeanDefinition是RootBeanDefinition,这时候就使用getMergedLocalBeanDefinition方法做了一次转化,将非RootBeanDefinition转换为RootBeanDefinition以供后续操作。
RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {//非抽象的,单例的,非懒加载的
if (isFactoryBean(beanName)) { //Spring中有两种类型的Bean,一种是普通Bean,另一种是工厂Bean,即FactoryBean, 工厂Bean 再起炉灶
final FactoryBean<?> factory = (FactoryBean<?>) getBean(FACTORY_BEAN_PREFIX + beanName);
boolean isEagerInit;
if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
isEagerInit = AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
@Override
public Boolean run() {
return ((SmartFactoryBean<?>) factory).isEagerInit();
}
}, getAccessControlContext());
}
else {
isEagerInit = (factory instanceof SmartFactoryBean &&
((SmartFactoryBean<?>) factory).isEagerInit());
}
if (isEagerInit) {
getBean(beanName);
}
}
else { //非工厂Bean 调用该方法
getBean(beanName);
}
}
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
这里出现了一个Bean(Factory Bean)
,可以说Spring
有一大半的扩展功能与这个Bean
有关,它是一个工厂Bean
,用于产生Bean
实例,如果一个类继承 FactoryBean
,用户可以自定义产生对象的方法,只需要实现它的getObject
方法即可。然而在Spring
内部,这个Bean
的实例对象是FactoryBean
通过调用这个对象的getObject
方法就能获取用户自定义产生的对象,从而为Spring
提供了很好的扩展性。Spring
获取FactoryBean
本身的对象是通过在前面加上&来完成的。
如何创建Bean
的实例对象及如何构建Bean
实例对象之间的关联关系是Spring
中的一个核心,还有就是建立Bean
对象实例之间的关系,也是Spring
框架的核心竞争力。Bean
实例创建流程图如下:

# 六、IOC
容器的扩展点
对Spring
的IOC
容器来说,主要有BeanFactoryPostProcessor
和BeanPostProcessor
,他们分别在构建BeanFactory
和构建Bean
对象时调用。还有就是InItializingBean
和DisposableBean
,他们分别在Bean
创建和销毁时调用。用户可以实现在这些接口中定义的方法,Spring
会在适当的时候调用它们。还有一个是FactoryBean
,它是个特殊的Bean
,可以被用户更多的控制。
这些扩展点通常也是我们使用Spring
来完成特殊任务的地方,如何精通Spring
就看是否掌握好Spring
有哪些扩展点,以及如何使用它们。要知道如何使用它们就必须了解它们内在的机制。
ApplicationContext.xml
就是IOC
容器的默认配置文件,Spring
的所有特性功能都是基于IOC
容器工作的。我们可以通过实现Spring
的扩展点来改变Spring
的通用行为。至于如何实现扩展点来得到我们想要的结果,在Spring
中有很多例子,其中AOP
的实现就是通过扩展点达到想要的特性功能,可以拿来参考。