五、spring源码阅读之ClassPathXmlApplicationContext加载beanFactory
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring-config.xml");
Spring加载xml数据的切入点是通过ClassPathXmlApplicationContext类进行切入的。该类是面向xml文件。类似的spring还提供了面向注解的解析类AnnotationConfigApplicationContext等。
进入
new ClassPathXmlApplicationContext("spring-config.xml");
之后代码如下:
public ClassPathXmlApplicationContext(
String[] configLocations, boolean refresh, @Nullable ApplicationContext parent)
throws BeansException {
super(parent);
setConfigLocations(configLocations);
if (refresh) {
refresh();
}
}
Spring容器的加载、xml文件的解析器以及单例、非懒加载的类等都是由refresh()方法完成。Refresh代码如下所示:
@Override
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// Prepare this context for refreshing.
//准备刷新环境列入对系统属性或者环境变量进行准备及验证
prepareRefresh();
// Tell the subclass to refresh the internal bean factory.
/* 调用子类AbstractRefreshableApplicationContext 刷新DefaultListableBeanFactory工厂
* 功能描述 1、创建核心组件ConfigurableListableBeanFactory
* 2、获取xml、注解等方式的配置,将其转换为原数据放入ConfigurableListableBeanFactory中
* 3、xml读取
*/
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) {
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();
}
}
}
如代码所示xml数据的读取主要是在obtainFreshBeanFactory()方法中进行处理的。而AbstractApplicationContext类中并没有对obtainFreshBeanFactory()方法做具体的实现,而是将其交由子类AbstractRefreshableApplicationContext去实现
Xml的读取主要处理2个问题
1、准备容器,用于存储解析后的数据
2、准备documentReader,用于解析spring配置文件
代码如下:
@Override
protected final void refreshBeanFactory() throws BeansException {
/**
* DefaultListableBeanFactory被实例化至少一次时将销毁spring创建的对象,并且关闭DefaultListableBeanFactory实例
*/
if (hasBeanFactory()) {
destroyBeans();
closeBeanFactory();
}
try {
DefaultListableBeanFactory beanFactory = createBeanFactory();//创建spring的核心组件
//为了序列化指定id
beanFactory.setSerializationId(getId());
//定制beanFactory,设置相关属性。
customizeBeanFactory(beanFactory);
//初始化xml读取器、读取原数据切入点 交由子类处理
loadBeanDefinitions(beanFactory);
synchronized (this.beanFactoryMonitor) {
this.beanFactory = beanFactory;
}
}
catch (IOException ex) {
throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
}
}
该方法主要完成以下几个工作:
1、校验DefaultListableBeanFactory被实例化至少一次时将销毁spring创建的对象,并且关闭DefaultListableBeanFactory实例
2、创建spring的核心组件DefaultListableBeanFactory的具体实例并设置相应参数,也就是beanFactory。
3、初始化xml读取器、读取xml数据切入点 交由子类处理。
4、将beanFactory设定为全局变量。
AbstractRefreshableApplicationContext并没有对loadBeanDefinitions()方法进行具体的实现,而是将其交由子类去做处理,这样做的好处是针对不同的spring配置方式采用不同的解析方式进行解析(策略模式)。
Ps:此处只针对xml文件的配置(AbstractXmlApplicationContext)解析进行说明
上面部分代码完成了对beanFactory的定制,并且对xml文件的解析做了切入loadBeanDefinitions();
@Override
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
// Create a new XmlBeanDefinitionReader for the given BeanFactory.
/*依据beanFactory创建新的XmlBeanDefinitionReader */
XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
// Configure the bean definition reader with this context's
// resource loading environment.
beanDefinitionReader.setEnvironment(this.getEnvironment());
beanDefinitionReader.setResourceLoader(this);
beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));
// Allow a subclass to provide custom initialization of the reader,
// then proceed with actually loading the bean definitions.
initBeanDefinitionReader(beanDefinitionReader);
loadBeanDefinitions(beanDefinitionReader);
}
以上代码完成以下功能
1、为特定的beanFactory准备相应的beanDefinitionReader 并完成相应设置
2、切入loadBeanDefinitions();
Xml文件的解析是交由专门的解析类AbstractBeanDefinitionReader进行处理。
protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {
Resource[] configResources = getConfigResources();
if (configResources != null) {
reader.loadBeanDefinitions(configResources);
}
String[] configLocations = getConfigLocations();
if (configLocations != null) {
reader.loadBeanDefinitions(configLocations);
}
}
Ps:读者可参考此图

五、spring源码阅读之ClassPathXmlApplicationContext加载beanFactory的更多相关文章
- 【Spring源码分析】Bean加载流程概览
代码入口 之前写文章都会啰啰嗦嗦一大堆再开始,进入[Spring源码分析]这个板块就直接切入正题了. 很多朋友可能想看Spring源码,但是不知道应当如何入手去看,这个可以理解:Java开发者通常从事 ...
- 【Spring源码分析】Bean加载流程概览(转)
转载自:https://www.cnblogs.com/xrq730/p/6285358.html 代码入口 之前写文章都会啰啰嗦嗦一大堆再开始,进入[Spring源码分析]这个板块就直接切入正题了. ...
- Spring源码分析:Bean加载流程概览及配置文件读取
很多朋友可能想看Spring源码,但是不知道应当如何入手去看,这个可以理解:Java开发者通常从事的都是Java Web的工作,对于程序员来说,一个Web项目用到Spring,只是配置一下配置文件而已 ...
- Spring源码解析-配置文件的加载
spring是一个很有名的java开源框架,作为一名javaer还是有必要了解spring的设计原理和机制,beans.core.context作为spring的三个核心组件.而三个组件中最重要的就是 ...
- 【Spring源码分析系列】加载Bean
/** * Create a new XmlBeanFactory with the given input stream, * which must be parsable using DOM. * ...
- Spring源码阅读-ApplicationContext体系结构分析
目录 继承层次图概览 ConfigurableApplicationContext分析 AbstractApplicationContext GenericApplicationContext Gen ...
- Spring源码阅读 之 配置的读取,解析
在上文中我们已经知道了Spring如何从我们给定的位置加载到配置文件,并将文件包装成一个Resource对象.这篇文章我们将要探讨的就是,如何从这个Resouce对象中加载到我们的容器?加载到容器后又 ...
- 初始化IoC容器(Spring源码阅读)
初始化IoC容器(Spring源码阅读) 我们到底能走多远系列(31) 扯淡: 有个问题一直想问:各位你们的工资剩下来会怎么处理?已婚的,我知道工资永远都是不够的.未婚的你们,你们是怎么分配工资的? ...
- 37 网络相关函数(五)——live555源码阅读(四)网络
37 网络相关函数(五)——live555源码阅读(四)网络 37 网络相关函数(五)——live555源码阅读(四)网络 简介 10)MAKE_SOCKADDR_IN构建sockaddr_in结构体 ...
随机推荐
- python接口自动化测试-unittest-生成测试报告
用例的管理问题解决了后,接下来要考虑的就是报告我问题了,这里生成测试报告主要用到 HTMLTestRunner.py 这个模块,下面简单介绍一下如何使用: 一.下载HTMLTestRunner下载: ...
- Vue+Vant+Vuex实现本地购物车功能
通常,我们做移动端商城的时候,通常会有购物车模块,那购物车模块有两种实现方式,一是储存在后台通过接口获取到购物车信息,二是存在用户手机本地,第一种方法只要调用接口获取比较简单,这里介绍的是第二种方法, ...
- SpringCloudAlibaba通过jib插件打包发布到docker仓库
序言 在SpringBoot项目部署的时候,我了解到了Jib插件的强大,这个插件可以快速构建镜像发布到我们的镜像仓库当中去.于是我打算在毕设当中加上这个功能,并且整合到github actions中去 ...
- Kubernetes 会不会“杀死” DevOps?
作者丨孙健波(天元) 阿里巴巴技术专家 导读:DevOps 这个概念最早是在 2007 年提出的,那时云计算基础设施的概念也才刚刚提出没多久,而随着互联网的逐渐普及,应用软件的需求爆发式增长,软件开 ...
- nginx 负载均衡的配置
首先搭建好三台nginx,我是用VM搭建的 nginx搭建,https://www.cnblogs.com/liubaoqing/p/10507962.html 这里的三台nginx ,ip分别是 1 ...
- JPA或Hibernate中使用原生SQL实现分页查询、排序
发生背景:前端展示的数据需要来自A表和D表拼接,A表和D表根据A表的主键进行关联,D表的非主键字段关联C表的主键,根据条件筛选出符合的数据,并且根据A表的主键关联B表的主键(多主键)的条件,过滤A表中 ...
- rust 打印当前时间
let now = time::now();let f_now = time::strftime("%Y-%m-%dT%H:%M:%S", &now).unwrap();p ...
- GC 为什么要挂起用户线程? 什么愁什么怨?
GC 为什么要挂起用户线程? 什么愁什么怨? 前言 JVM 系列文章的第一篇.敬请期待后续. 故障描述 某年某月某日 上午,线上发生故障,经过排查,发现某核心服务 Dubbo 接口超时. 故障根源 查 ...
- SpringBoot2 整合Nacos组件,环境搭建和入门案例详解
本文源码:GitHub·点这里 || GitEE·点这里 一.Nacos基础简介 1.概念简介 Nacos 是构建以"服务"为中心的现代应用架构,如微服务范式.云原生范式等服务基础 ...
- 小程序中button标签的open-type属性
open-type (微信开放能力):合法值中的其中之一: getUserInfo 说明:引导用户授权 而获取用户信息,可以从bindgetuserinfo回调中获取到用户信息 而按钮的bi ...