2019年的第一篇文章,新的一年的计划是完成11*3,33篇文章,每一篇文章都会花至少2个小时进行创作。加油啦。
1 前言
Spring为开发者提供了一个一站式的轻量应用开发框架(平台)。在Spring中IOC容器和AOP模块是两大核心,类似与操作系统的Kernel。
通过使用Spring的IOC容器,可以对Java对象中的耦合关系方便的进行浏览,修改和维护。原来的对象-对象的关系,转化为了对象-IOC容器-对象的关系。完成了对象之间的关系解耦。本篇文章就准备从整体和细节角度分析一下Spring核心容器之一的IOC容器的实现。
2 Spring IOC容器的内容
Spring IoC:包含了最基本的IoC容器BeanFactory的接口和实现。ApplicationContext作为BeanFactory的高级形态供用户进行使用。ApplicationContext应用上下文,如FileSystemXmlApplicationContext,ClassPathXmlApplicationContext 是IoC容器中更面向框架的使用方式。为了便于开发,像国际化的消息源和应用支持事件这些特性,也都围绕这个模块中配合IoC容器来实现,这些功能围绕IoC基本容器和应用上下问,构成了整个Spring IoC模块设计的重要内容。
3 代码分析
3.1 IoC容器整体设计
Spring的Bean组件在org.springframework.beans包下,在这个包下面得解决了:Bean 的定义,Bean 的创建和Bean的解析。对于Spring的使用者来说主要关心的是这个Bean的创建过程。Bean的创建是典型的工厂模式,以BeanFactroy为核心。
这里从ApplicationContext着手开始分析,从ApplicationContext的类关系图中可以看到如下:
- BeanFactory是基本的IoC容器 :从接口BeanFactory到HierarchicalBeanFactory再到ApplicationContext。在BeanFactory中定义了基本的IoC容器的规范,包含了getBean这样的IoC容器的基本方法。而HierarchicalBeanFactory在继承了BeanFactory之后是添加了getParentBeanFactory的接口功能。使得当前的BeanFactory具备了双亲IoC容器的管理功能。
-
ApplicationContext是一个高级形态的IoC容器:我们常用的应用上下文基本都是ConfigurableApplicationContext或WebApplicationContext。都是继承自ApplicaitonContext的。对于ApplicaitonContext接口,通过继承MessageSource,ResourceLoader,ApplicationEventPublisher从而完成了在BeanFactory基础上的许多高级特性的支持。
3.1.1 BeanFactory分析
BeanFactory 接口定义了IoC容器的基本形式和应当遵守的基本契约,并没有具体的实现。
接着我们来看看BeanFactory的一个实现类XmlBeanFactory的继承类图:
在Spring中,把DefaultListableBeanFactory当作一个默认的功能完整的IoC容器来使用。 XmlBeanFactory在继承了DefaultListableBeanFactory的基础上,增加支持读取XML文件的方式定义了这个IoC容器。如下所示:
类比ApplicationContext:我们可以看到的是XmlBeanFactory使用了DefaultListableBeanFactory作为基类。类似于我们之前的ApplicationContext,实现原理也和XmlBeanFactory一样,也是通过持有或者拓展BeanFactory的子类来实现IoC容器的功能。
由于XmlBeanFactory文档中已经标记为@deprecated的类,所以我们这里根据远离,使用编程的方式实现IoC容器的的过程,和上面XmlBeanFactory一样:
3.1.2 ApplicationContext分析
上面提到,ApplicationContext是一个高级形态的IoC容器,那么ApplicationContext提供了哪一些BeanFactory不具备的特性?
这里我们可以从上面ApplicationContext的继承关系图中看到,出了延伸于BeanFactory的类的话,其他就是BeanFactory不具有的特性,如:
- 支持不同的信息源,通过扩展MessageSource实现。
- 访问资源。通过对ResourceLoader和Resource的支持上,可以从不同地方得到Bean定义资源。
- 支持应用事件。继承了接口ApplicationEventPublisher,从而在上下文中引入了事件机制。
3.2 IoC容器如何工作
3.2.1 以FileSystemXmlApplicationContext为入口
这里以FileSystemXmlApplicationContext 为入口,看看IoC容器是如何工作的。
在FileSystemXmlApplicationContext的设计中,主要关注的是这个refresh()过程,这会牵涉IoC容器启动的一系列复杂的操作都在这里面,但是这是在AbstractApplicationContext中实现的。不同的应用上下文对应着不同的读取BeanDefinition的方法,在FileSystemXmlApplicationContext中如下getResourcePath所示。
这里明确,以AbstractApplicationContext类 为研究中心
3.2.2 BeanFactory加载
代码片段1 这里来自以AbstractApplicationContext类 的refresh方法
@Override
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// 为刷新准备新的context
prepareRefresh();
// 刷新所有BeanFactory子容器
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// 创建BeanFactory后,添加一些Spring 需要的工具类
prepareBeanFactory(beanFactory);
try {
// 在Bean Factory 初始化之后,可以继续配置更改
postProcessBeanFactory(beanFactory);
//执行BeanFactoryPostProcessor
invokeBeanFactoryPostProcessors(beanFactory);
// 创建Bean实例对象时添加一些自定义的操作
registerBeanPostProcessors(beanFactory);
// 初始化MessageSource
initMessageSource();
//初始化event multicaster
initApplicationEventMulticaster();
// 刷新由子类实现的方法
onRefresh();
// 检查和注册事件
registerListeners();
// 初始化non-lazy-init 单例bean
finishBeanFactoryInitialization(beanFactory);
// event事件
finishRefresh();
}
catch (BeansException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - " +
"cancelling refresh attempt: " + ex);
}
// 销毁beans
destroyBeans();
cancelRefresh(ex);
throw ex;
}
finally {
// Reset common introspection caches in Spring's core, since we
// might not ever need metadata for singleton beans anymore...
resetCommonCaches();
}
}
}
这个方法是构建整个IoC容器的完整代码,了解里面的每一行代码,就了解了大部分Spring的原理和功能。
总结一下这段代码包含的步骤:
- (1)构建BeanFactory,用于创建Bean
- (2)注册可能感兴趣的事件
- (3) 创建Bean实例对象
- (4)触发被监听的事件
在上面的过程中,创建和配置BeanFactory,刷新配置的步骤由obtainFreshBeanFactory()方法完成,
进入方法内部,主要是刷新和获取BeanFactory
刷新beanFactory交给子类去实现,这里是AbstractRefreshableApplicationContext中实现代码:
上图所示的createBeanFactory会调用DefaultListableBeanFactory的createBeanFactory方法。然后下方的loadBeanDefinitions会进入
AbstractXmlApplicationContext的loadBeanDefinitions方法,到这里应该就完成了BeanFactory的创建工作。
接着回到代码清单1中,我们关注到 registerBeanPostProcessors(beanFactory)方法,也可以获取用户定义实现了BeanPostProcessor接口的子类。并把它注册到BeanFactory对象中的beanPostProcessors变量中。在BeanPostProcessor中声明了两个方法:
分别用于在Bean对象初始化时执行,可以执行用户自定义的操作。
3.2.3 创建Bean实例
回到代码清单1 ,Bean的实例化代码,是从 finishBeanFactoryInitialization(beanFactory)方法开始的。
@Override
public void preInstantiateSingletons() throws BeansException {
if (this.logger.isDebugEnabled()) {
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<String> beanNames = new ArrayList<String>(this.beanDefinitionNames);
// Trigger initialization of all non-lazy singleton beans...
for (String beanName : beanNames) {
RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
if (isFactoryBean(beanName)) {
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 {
getBean(beanName);
}
}
}
// Trigger post-initialization callback for all applicable beans...
for (String beanName : beanNames) {
Object singletonInstance = getSingleton(beanName);
if (singletonInstance instanceof SmartInitializingSingleton) {
final SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;
if (System.getSecurityManager() != null) {
AccessController.doPrivileged(new PrivilegedAction<Object>() {
@Override
public Object run() {
smartSingleton.afterSingletonsInstantiated();
return null;
}
}, getAccessControlContext());
}
else {
smartSingleton.afterSingletonsInstantiated();
}
}
}
}
如果一个类继承FactoryBean,用户可以自己定义产生实例对象的方法,只需实现它的getObject方法就可以了。这就上上面代码中出现的FactoryBean。Spring获取FactoryBean本身的对象是通过在前面加上&来完成的。
网友评论