转载 https://mp.weixin.qq.com/s?__biz=MzI0NjUxNTY5Nw==&mid=2247483835&idx=1&sn=276911368d443f134997408a75578daa&scene=19#wechat_redirect

框架的源码分析,有些代码可以暂时忽略,如Spring如何进行XML模式校验的、XML解析的细节等,这些代码可以在了解了整体的原理之后,再做针对性的分析,关注重点内容即可,切记在一开始就去深挖每个细节,这样不仅会耗费很长时间,而且容易陷入某个坑里出不来。

以《深入理解Spring系列之一:开篇》示例中的ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationgContext.xml")为入口,进入源码内部,ClassPathXmlApplicationContext类图如下所示。

ClassPathXmlApplicationContext有多个构造方法,跟踪代码可以发现,最终使用的是下面这个方法,

	public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)
throws BeansException { super(parent);
setConfigLocations(configLocations);
if (refresh) {
refresh();
}
}

方法的参数很容易理解,configLocations指Spring的xml配置文件;refresh指是否需要刷新,这个refresh决定了是否进行bean解析、注册及实例化;parent指父ApplicationContext

setConfigLocations方法就是设置框架要加载的资源文件的位置。进入refresh方法,这个方法继承自AbstractApplicationContext,所以具体实现在AbstractApplicationContext类中,具体代码如下。

@Override
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
//容器预先准备,记录容器启动时间和标记
prepareRefresh(); //创建bean工厂,里面实现了BeanDefinition的装载
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); //配置bean工厂的上下文信息,如类装载器等
prepareBeanFactory(beanFactory); try {
//在BeanDefinition被装载后,提供一个修改BeanFactory的入口
postProcessBeanFactory(beanFactory); //在bean初始化之前,提供对BeanDefinition修改入口,PropertyPlaceholderConfigurer 在这里被调用
invokeBeanFactoryPostProcessors(beanFactory); //注册各种 BeanPostProcessors,用于在bean被初始化时进行拦截,进行额外初始化操作
registerBeanPostProcessors(beanFactory); //初始化MessageSource
initMessageSource(); //初始化上下文事件广播
initApplicationEventMulticaster(); //这是一个模板方法
onRefresh(); //注册监听器
registerListeners(); //初始化所有未初始化的非懒加载的单例Bean
finishBeanFactoryInitialization(beanFactory); //发布事件通知
finishRefresh();
} catch (BeansException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - " +
"cancelling refresh attempt: " + ex);
} // Destroy already created singletons to avoid dangling resources.
destroyBeans(); // Reset 'active' flag.
cancelRefresh(ex); // Propagate exception to caller.
throw ex;
} finally {
// Reset common introspection caches in Spring's core, since we
// might not ever need metadata for singleton beans anymore...
resetCommonCaches();
}
}
}

这个方法里面就是IOC容器初始化的大致步骤了。上面步骤的第二步完成了BeanDefinition的装载,进入obtainFreshBeanFactory方法,这个方法的具体实现也在AbstractApplicationContext类中,代码如下所示。

protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
refreshBeanFactory();
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
if (logger.isDebugEnabled()) {
logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);
}
return beanFactory;
}

这里面主要关注refreshBeanFactory方法,这个方法在AbstractApplicationContext类中并未实现,具体实现在子类AbstractRefreshableApplicationContext中,代码如下。

@Override
protected final void refreshBeanFactory() throws BeansException {
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);
}
}

这个方法使用了final修饰,也就是不能被重写了。首先检查BeanFactory是否已经存在,如果存在则销毁并关闭,然后新建一个 BeanFactory,其实就是一个DefaultListableBeanFactory,这个DefaultListableBeanFactory就是《深入理解Spring系列之一:开篇》说的那个。然后进行BeanFactory的属性设置,设置是否允许重写BeanDefinition、是否允许循环引用,接着loadBeanDefinitions方法就是BeanDefinition载入的入口了,这个方法在AbstractRefreshableApplicationContext本类中并未实现,具体在其子类中实现,根据用途不同有多个实现子类,下一篇内容将分析基于最基本的解析xml方式的AbstractXmlApplicationContext类中的实现。

loadBeanDefinitions方法 的具体实现类

深入理解Spring系列之四:BeanDefinition装载前奏曲的更多相关文章

  1. 深入理解Spring系列之五:BeanDefinition装载

    转载 https://mp.weixin.qq.com/s/1_grvpJYe8mMIAnebMdz9Q 接上篇<深入理解Spring系列之四:BeanDefinition装载前奏曲>,进 ...

  2. 深入理解Spring系列之七:web应用自动装配Spring配置

    转载 https://mp.weixin.qq.com/s/Lf4akWFmcyn9ZVGUYNi0Lw 在<深入理解Spring系列之一:开篇>的示例代码中使用如下方式去加载Spring ...

  3. 深入理解Spring系列之六:bean初始化

    转载 https://mp.weixin.qq.com/s/SmtqoELzBEdZLo8wsSvUdQ <深入理解Spring系列之四:BeanDefinition装载前奏曲>中提到,对 ...

  4. 深入理解Spring系列之二:BeanDefinition解析

    转载 https://mp.weixin.qq.com/s?__biz=MzI0NjUxNTY5Nw==&mid=2247483814&idx=1&sn=ddf49931d55 ...

  5. 深入理解Spring系列之三:BeanFactory解析

    转载 https://mp.weixin.qq.com/s?__biz=MzI0NjUxNTY5Nw==&mid=2247483824&idx=1&sn=9b7c2603093 ...

  6. 深入理解Spring系列之一:开篇

    转载 https://mp.weixin.qq.com/s?__biz=MzI0NjUxNTY5Nw==&mid=2247483810&idx=1&sn=a2df14fdb63 ...

  7. 深入理解Spring系列之十二:@Transactional是如何工作的

    转载 https://mp.weixin.qq.com/s/ZwhkUQF1Nun9pNrFI-3a6w 首先从说起.配置了,就必定有对应的标签解析器类,查看NamespaceHandler接口的实现 ...

  8. 深入理解Spring系列之八:常用的扩展接口

    转载 https://mp.weixin.qq.com/s/XfhZltSlTall8wKwV_7fKg Spring不仅提供了一个进行快速开发的基础框架,而且还提供了很多可扩展的接口,用于满足一些额 ...

  9. 深入理解Spring系列之十:DispatcherServlet请求分发源码分析

    转载 https://mp.weixin.qq.com/s/-kEjAeQFBYIGb0zRpST4UQ DispatcherServlet是SpringMVC的核心分发器,它实现了请求分发,是处理请 ...

随机推荐

  1. Linux服务器启动后只读解决办法

    今天处理一个服务器,远程死活连接不上,只好跑信息中心去看了下服务器. Linux服务器启动之后,提示: give root password for maintenance (or type cont ...

  2. MySQL专题 1 分布式部署数据库同步问题 BinLog

    什么是 Binlog MySQL Server 有四种类型的日志——Error Log.General Query Log.Binary Log 和 Slow Query Log. 第一个是错误日志, ...

  3. windows下面安装redis

    一.下载windows版本的Redis 链接:https://pan.baidu.com/s/1i6X2klv 密码:j4pi 二.安装Redis 这里下载的是Redis-x64-3.2.100版本, ...

  4. 第132天:移动web端-rem布局(进阶)

    rem布局(进阶版) 该方案使用相当简单,把下面这段已压缩过的 原生JS(仅1kb,源码已在文章底部更新,2017/5/3) 放到 HTML 的 head 标签中即可(注:不要手动设置viewport ...

  5. robot framework Selenium2关键字介绍

    *** Settings *** Library Selenium2Library *** Keywords *** Checkbox应该不被选择 [Arguments] ${locator} Che ...

  6. BZOJ4922 Karp-de-Chant Number(贪心+动态规划)

    首先将每个括号序列转化为三元组(ai,bi,ci),其中ai为左括号-右括号数量,bi为前缀最小左括号-右括号数,ci为序列长度.问题变为在满足Σai=0,bi+Σaj>=0 (j<i)的 ...

  7. [BZOJ4653][NOI2016]区间 贪心+线段树

    4653: [Noi2016]区间 Time Limit: 60 Sec  Memory Limit: 256 MB Description 在数轴上有 n个闭区间 [l1,r1],[l2,r2],. ...

  8. 转: 解决【Unable to make the session state request to the session state server】

    错误描述: Unable to make the session state request to the session state server. Please ensure that the A ...

  9. 常州day1p5

    给一个 n∗m 的矩阵,矩阵的每个格子上有一个不超过 30 的非负整数. 我们定义一条合法的路线是从(1,1)开始只能向右和向下移动到达(n,m)的路线. 定义数列 A1,A2,A3,..,An+m− ...

  10. BZOJ1563/洛谷P1912 诗人小G 【四边形不等式优化dp】

    题目链接 洛谷P1912[原题,需输出方案] BZOJ1563[无SPJ,只需输出结果] 题解 四边形不等式 什么是四边形不等式? 一个定义域在整数上的函数\(val(i,j)\),满足对\(\for ...