Ioc 容器如何工作
前面介绍了 Core 组件、Bean 组件和 Context 组件的结构与相互关系,下面这里从使用者角度看一下他们是如何运行的,以及我们如何让 Spring 完成各种功能,Spring 到底能有那些功能,这些功能是如何得来的,下面介绍。
如何创建 BeanFactory 工厂
正如图 2 描述的那样,Ioc 容器实际上就是 Context 组件结合其他两个组件共同构建了一个 Bean 关系网,如何构建这个关系网?构建的入口就在 AbstractApplicationContext 类的 refresh 方法中。这个方法的代码如下:
清单 1. AbstractApplicationContext.refresh
synchronized (this.startupShutdownMonitor) {
// Prepare this context for refreshing.
prepareRefresh();
// Tell the subclass to refresh the internal bean factory.
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// Prepare the bean factory for use in this context.
prepareBeanFactory(beanFactory);
try {
// Allows post-processing of the bean factory in context subclasses.
postProcessBeanFactory(beanFactory);
// Invoke factory processors registered as beans in the context.
invokeBeanFactoryPostProcessors(beanFactory);
// Register bean processors that intercept bean creation.
registerBeanPostProcessors(beanFactory);
// Initialize message source for this context.
initMessageSource();
// Initialize event multicaster for this context.
initApplicationEventMulticaster();
// Initialize other special beans in specific context subclasses.
onRefresh();
// Check for listener beans and register them.
registerListeners();
// Instantiate all remaining (non-lazy-init) singletons.
finishBeanFactoryInitialization(beanFactory);
// Last step: publish corresponding event.
finishRefresh();
}
catch (BeansException ex) {
// Destroy already created singletons to avoid dangling resources.
destroyBeans();
// Reset 'active' flag.
cancelRefresh(ex);
// Propagate exception to caller.
throw ex;
}
}
}
这个方法就是构建整个 Ioc 容器过程的完整的代码,了解了里面的每一行代码基本上就了解大部分 Spring 的原理和功能了。
这段代码主要包含这样几个步骤:
1.注册可能感兴趣的事件
2.创建 Bean 实例对象
3.触发被监听的事件
下面就结合代码分析这几个过程。
第二三句就是在创建和配置 BeanFactory。这里是 refresh 也就是刷新配置,前面介绍了 Context 有可更新的子类,这里正是实现这个功能,当 BeanFactory 已存在是就更新,如果没有就新创建。下面是更新 BeanFactory 的方法代码:
清单 2. AbstractRefreshableApplicationContext. refreshBeanFactory
if (hasBeanFactory()) {
destroyBeans();
closeBeanFactory();
}
try {
DefaultListableBeanFactory beanFactory = createBeanFactory();
beanFactory.setSerializationId(getId());
customizeBeanFactory(beanFactory);
loadBeanDefinitions(beanFactory);
synchronized (this.beanFactoryMonitor) {
this.beanFactory = beanFactory;
}
}
catch (IOException ex) {
throw new ApplicationContextException(
"I/O error parsing bean definition source for "
+ getDisplayName(), ex);
}
}
这个方法实现了 AbstractApplicationContext 的抽象方法 refreshBeanFactory,这段代码清楚的说明了 BeanFactory 的创建过程。注意 BeanFactory 对象的类型的变化,前面介绍了他有很多子类,在什么情况下使用不同的子类这非常关键。BeanFactory 的原始对象是 DefaultListableBeanFactory,这个非常关键,因为他设计到后面对这个对象的多种操作,下面看一下这个类的继承层次类图:
图 10. DefaultListableBeanFactory 类继承关系图
从这个图中发现除了 BeanFactory 相关的类外,还发现了与 Bean 的 register 相关。这在 refreshBeanFactory 方法中有一行 loadBeanDefinitions(beanFactory) 将找到答案,这个方法将开始加载、解析 Bean 的定义,也就是把用户定义的数据结构转化为 Ioc 容器中的特定数据结构。
这个过程可以用下面时序图解释:
图 11. 创建 BeanFactory 时序图
Bean 的解析和登记流程时序图如下:
图 12. 解析和登记 Bean 对象时序图
创建好 BeanFactory 后,接下去添加一些 Spring 本身需要的一些工具类,这个操作在 AbstractApplicationContext 的 prepareBeanFactory 方法完成。
AbstractApplicationContext 中接下来的三行代码对 Spring 的功能扩展性起了至关重要的作用。前两行主要是让你现在可以对已经构建的 BeanFactory 的配置做修改,后面一行就是让你可以对以后再创建 Bean 的实例对象时添加一些自定义的操作。所以他们都是扩展了 Spring 的功能,所以我们要学习使用 Spring 必须对这一部分搞清楚。
其中在 invokeBeanFactoryPostProcessors 方法中主要是获取实现 BeanFactoryPostProcessor 接口的子类。并执行它的 postProcessBeanFactory 方法,这个方法的声明如下:
清单 3. BeanFactoryPostProcessor.postProcessBeanFactory
void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory)
throws BeansException;
它的参数是 beanFactory,说明可以对 beanFactory 做修改,这里注意这个 beanFactory 是 ConfigurableListableBeanFactory 类型的,这也印证了前面介绍的不同 BeanFactory 所使用的场合不同,这里只能是可配置的 BeanFactory,防止一些数据被用户随意修改。
registerBeanPostProcessors 方法也是可以获取用户定义的实现了 BeanPostProcessor 接口的子类,并执行把它们注册到 BeanFactory 对象中的 beanPostProcessors 变量中。BeanPostProcessor 中声明了两个方法:postProcessBeforeInitialization、postProcessAfterInitialization 分别用于在 Bean 对象初始化时执行。可以执行用户自定义的操作。
后面的几行代码是初始化监听事件和对系统的其他监听者的注册,监听者必须是 ApplicationListener 的子类。