SpringIOC分析(Xml配置)02
xsobi 2024-11-24 23:34 1 浏览
3.开始启动
SpringlOC容器对Bean配置资源的载入是从refresh()函数开始的,refresh()是一个模板方法,规定了IOC容器的启动流程,有些逻辑要交给其子类去实现。它对Bean配置资源进行载入ClassPathXmlApplicationContext 通过调用其父类AbstractApplicationContext的refresh()函数启动整个IOC容器对Bean定义的载入过程,现在我们来详细看看refresh()中的逻辑处理:
// 启动整个IOC容器对Bean定义的载入过程
@Override
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// Prepare this context for refreshing.
// 1.调用容器准备刷新的方法获取勇气的当时时间,同时给容器设置同步标识
prepareRefresh();
// Tell the subclass to refresh the internal bean factory.
// 2.告诉子类启动 refreshBeanFactory() 方法,Bean定义资源文件的载入从子类的 refreshBeanFactory() 方法启动
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// Prepare the bean factory for use in this context.
// 3.为Beanfactory配置容器特性,例如类加载器,事件处理器等
prepareBeanFactory(beanFactory);
try {
// Allows post-processing of the bean factory in context subclasses.
// 4.为容器的某些子类指定特殊的BeanPost事件处理器
postProcessBeanFactory(beanFactory);
// Invoke factory processors registered as beans in the context.
// 5.调用所有注册的 BeanFactoryPostProcessors 的Bean
invokeBeanFactoryPostProcessors(beanFactory);
// Register bean processors that intercept bean creation.
// 6.为beanFactory 注册 BeanPost事件处理器
registerBeanPostProcessors(beanFactory);
// Initialize message source for this context.
// 7.初始化信息源,和国际化相关
initMessageSource();
// Initialize event multicaster for this context.
// 8.初始化容器事件传播器
initApplicationEventMulticaster();
// Initialize other special beans in specific context subclasses.
// 9.调用子类的某些特殊Bean初始化方法
onRefresh();
// Check for listener beans and register them.
// 10.为事件传播器注册事件监听器
registerListeners();
// Instantiate all remaining (non-lazy-init) singletons.
// 11.初始化所有神域的单例Bean
finishBeanFactoryInitialization(beanFactory);
// Last step: publish corresponding event.
// 12.初始化容器的生命周期事件处理器,并发布容器的生命周期事件
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.
// 13.销毁已创建的Bean
destroyBeans();
// Reset 'active' flag.
// 14.起效refresh操作,重置容器的同步标识
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...
// 15.重设公共缓存
resetCommonCaches();
}
}
}
refresh()方法主要为IOC容器Bean的生命周期管理提供条件,Spring IOC 容器载入Bean配置信息从其子类容器的refreshBeanFactory()方法启动,所以整个refresh()中 "ConfigurablelListableBeanFactory beanFactory = obtainFreshBeanfactory();"这句以后代码的都是注册容器的信息源和生命周期事件,我们前面说的载入就是从这句代码开始启动。
refresh()方法的主要作用是:在创建IOC容器前,如果已经有容器存在,则需要把已有的容器销毁和关闭,以保证在refresh之后使用的是新建立起来的IOC容器。它类似于对IOC容器的重启,在新建立好的容器中对容器进行初始化,对Bean配置资源进行载入。
4.创建容器
obtainFreshBeanfactory()方法调用子类容器的 refreshBeanFactory()方法,启动容器载入Bean配置信息的过程,代码如下:
/**
* Tell the subclass to refresh the internal bean factory.
* @return the fresh BeanFactory instance
* @see #refreshBeanFactory()
* @see #getBeanFactory()
*/
// 注册容器信息源和生命周期事件
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
// 这里使用了委派模式,父类定义抽象 refreshBeanFactory() 方法,具体实现调用子类容器
// 的 refreshBeanFactory() 方法
refreshBeanFactory();
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
if (logger.isDebugEnabled()) {
logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);
}
return beanFactory;
}
AbstractApplicationContext 类中只抽象定义了refreshBeanFactory()方法,容器真正调用的是 其子类AbstractRefreshableApplicationContext实现的refreshBeanFactory()方法,方法的源 码如下:
/**
* This implementation performs an actual refresh of this context's underlying
* bean factory, shutting down the previous bean factory (if any) and
* initializing a fresh bean factory for the next phase of the context's lifecycle.
*/
@Override
protected final void refreshBeanFactory() throws BeansException {
// 如果已经有容器,销毁容器中的bean,关闭容器
if (hasBeanFactory()) {
destroyBeans();
closeBeanFactory();
}
try {
// 创建IOC容器
DefaultListableBeanFactory beanFactory = createBeanFactory();
beanFactory.setSerializationId(getId());
// 对IOC容器进行定制化,如设置启动参数,开启注解的自动装配等
customizeBeanFactory(beanFactory);
// 调用载入bean 定义的方法,主要这里又使用了委派模式,在当前类中定义了抽象
// 的 loadBeanDefinitions 方法,具体的实现调用子类容器
loadBeanDefinitions(beanFactory);
this.beanFactory = beanFactory;
}
catch (IOException ex) {
throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
}
}
在这个方法中,先判断BeanFactory是否存在,如果存在则先销毁 beans并关闭beanFactory,接着 创建DefaultListableBeanFactory,并调用loadBeanDefinitions(beanFactory)装载 bean定义。
5.载入配置路径
AbstractRefreshableApplicationContext中只定义了抽象的loadBeanDefinitions 方法,容器真正调 用的是其子类AbstractXmlApplicationContext对该方法的实现,AbstractXmlApplicationContext 的主要源码如下:
loadBeanDefinitions0方法同样是抽象方法,是由其子类实现的,也即在 AbstractXmlApplicationContext中。
/**
* Loads the bean definitions via an XmlBeanDefinitionReader.
* @see org.springframework.beans.factory.xml.XmlBeanDefinitionReader
* @see #initBeanDefinitionReader
* @see #loadBeanDefinitions
*/
// 实现父类抽象的载入Bean方法
@Override
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
// 创建XmlBeanDefinitionReader,即创建Bean读取器,并通过回调设置到容器中去,容器使用该读取器读取Bean配置资源
// Create a new XmlBeanDefinitionReader for the given BeanFactory.
XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
// Configure the bean definition reader with this context's
// resource loading environment.
//
beanDefinitionReader.setEnvironment(this.getEnvironment());
beanDefinitionReader.setResourceLoader(this);
// 为Bean读取器设置SAX xml解析器
beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));
// Allow a subclass to provide custom initialization of the reader,
// then proceed with actually loading the bean definitions.
// 当bean读取器读取bean定义的xml资源文件时,启用xml的校验机制
initBeanDefinitionReader(beanDefinitionReader);
// bean读取器真正实现加载的方法
loadBeanDefinitions(beanDefinitionReader);
}
/**
* Initialize the bean definition reader used for loading the bean
* definitions of this context. Default implementation is empty.
* <p>Can be overridden in subclasses, e.g. for turning off XML validation
* or using a different XmlBeanDefinitionParser implementation.
* @param reader the bean definition reader used by this context
* @see org.springframework.beans.factory.xml.XmlBeanDefinitionReader#setDocumentReaderClass
*/
protected void initBeanDefinitionReader(XmlBeanDefinitionReader reader) {
reader.setValidating(this.validating);
}
/**
* Load the bean definitions with the given XmlBeanDefinitionReader.
* <p>The lifecycle of the bean factory is handled by the {@link #refreshBeanFactory}
* method; hence this method is just supposed to load and/or register bean definitions.
* @param reader the XmlBeanDefinitionReader to use
* @throws BeansException in case of bean registration errors
* @throws IOException if the required XML document isn't found
* @see #refreshBeanFactory
* @see #getConfigLocations
* @see #getResources
* @see #getResourcePatternResolver
*/
// xml bean读取器加载bean配置资源
protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {
// 获取bean配置资源的定位
Resource[] configResources = getConfigResources();
if (configResources != null) {
// xml bean读取器调用其父类AbstractBeanDefinitionReader读取定位的bean配置资源
reader.loadBeanDefinitions(configResources);
}
// 如果子类中获取的bean配置资源定位为空,则获取ClassPathXmlApplicationContext
// 构造方法中setConfigLocations方法设置的资源
String[] configLocations = getConfigLocations();
if (configLocations != null) {
// XML bean读取器调用其父类AbstractBenaDefinitionReader读取定位的Bean配置资源
reader.loadBeanDefinitions(configLocations);
}
}
/**
* Return an array of Resource objects, referring to the XML bean definition
* files that this context should be built with.
* <p>The default implementation returns {@code null}. Subclasses can override
* this to provide pre-built Resource objects rather than location Strings.
* @return an array of Resource objects, or {@code null} if none
* @see #getConfigLocations()
*/
// 这里又使用委派模式,调用子类获取bean配置资源定位的方法
// 该方法在ClassPathXmlApplicationContext中进行实现
@Nullable
protected Resource[] getConfigResources() {
return null;
}
以XmlBean读取器的其中一种策略XmlBeanDefinitionReader为例。XmlBeanDefinitionReader调 用其父类AbstractBeanDefinitionReader的reader.loadBeanDefinitions()方法读取Bean配置资源。 由于我们使用ClassPathXmlApplicationContext作为例子分析,因此getConfigResources的返回值 为null,因此程序执行 reader.loadBeanDefinitions(configLocations)分支。
6.分配路径处理策略
在XmlBeanDefinitionReader的抽象父类AbstractBeanDefinitionReader中定义了载入过程。
AbstractBeanDefinitionReader的 loadBeanDefinitions0方法源码如下:
@Override
public int loadBeanDefinitions(String location) throws BeanDefinitionStoreException {
return loadBeanDefinitions(location, null);
}
/**
* Load bean definitions from the specified resource location.
* <p>The location can also be a location pattern, provided that the
* ResourceLoader of this bean definition reader is a ResourcePatternResolver.
* @param location the resource location, to be loaded with the ResourceLoader
* (or ResourcePatternResolver) of this bean definition reader
* @param actualResources a Set to be filled with the actual Resource objects
* that have been resolved during the loading process. May be {@code null}
* to indicate that the caller is not interested in those Resource objects.
* @return the number of bean definitions found
* @throws BeanDefinitionStoreException in case of loading or parsing errors
* @see #getResourceLoader()
* @see #loadBeanDefinitions(org.springframework.core.io.Resource)
* @see #loadBeanDefinitions(org.springframework.core.io.Resource[])
*/
public int loadBeanDefinitions(String location, @Nullable Set<Resource> actualResources) throws BeanDefinitionStoreException {
// 获取在IOC容器初始化过程中设置的资源加载器
ResourceLoader resourceLoader = getResourceLoader();
if (resourceLoader == null) {
throw new BeanDefinitionStoreException(
"Cannot import bean definitions from location [" + location + "]: no ResourceLoader available");
}
if (resourceLoader instanceof ResourcePatternResolver) {
// Resource pattern matching available.
try {
// 将指定位置的bean配置信息解析为SpirngIOC容器封装的资源
// 加载多个指定位置的bean配置信息
Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(location);
// 委派调用其子类XmlBeanDefinitionReader的方法,实现加载功能
int loadCount = loadBeanDefinitions(resources);
if (actualResources != null) {
for (Resource resource : resources) {
actualResources.add(resource);
}
}
if (logger.isDebugEnabled()) {
logger.debug("Loaded " + loadCount + " bean definitions from location pattern [" + location + "]");
}
return loadCount;
}
catch (IOException ex) {
throw new BeanDefinitionStoreException(
"Could not resolve bean definition resource pattern [" + location + "]", ex);
}
}
else {
// Can only load single resources by absolute URL.
// 将制定位置的Bean配置信息解析为SpringIOC容器封装的资源
// 加载单个指定位置的bean配置信息
Resource resource = resourceLoader.getResource(location);
// 委派调用其子类XmlBeanDefinitionReader的方法,实现加载功能
int loadCount = loadBeanDefinitions(resource);
if (actualResources != null) {
actualResources.add(resource);
}
if (logger.isDebugEnabled()) {
logger.debug("Loaded " + loadCount + " bean definitions from location [" + location + "]");
}
return loadCount;
}
}
// 重载方法,调用loadBeanDefinitions
@Override
public int loadBeanDefinitions(String... locations) throws BeanDefinitionStoreException {
Assert.notNull(locations, "Location array must not be null");
int counter = 0;
for (String location : locations) {
counter += loadBeanDefinitions(location);
}
return counter;
}
AbstractRefreshableConfigApplicationContext的 loadBeanDefinitions(Resource... resources)方 法实际上是调用AbstractBeanDefinitionReader的loadBeanDefinitions0方法。
从对AbstractBeanDefinitionReader的loadBeanDefinitions()方法源码分析可以看出该方法就做了 两件事:
首先,调用资源加载器的获取资源方法resourceLoadergetResource(location)获取到要加载的资源。 其次,真正执行加载功能是其子类XmlBeanDefinitionReader的loadBeanDefinitions()方法。在 loadBeanDefinitions()方法中调用了AbstractApplicationContext的getResources()方法,跟进去之 后发现getResources()方法其实定义在ResourcePatternResolver中,此时,我们有必要来看一下 ResourcePatternResolver的全类图:
从上面可以看到ResourceLoader与ApplicationContext的继承关系,可以看出其实际调用的是 DefaultResourceloader 中的getSource()方法定位Resource,因为 ClassPathXmlApplicationContext 本身就是DefaultResourceLoader的实现类,所以此时又回到了 ClassPathXmlApplicationContext中来。
相关推荐
- bootstrap入门
-
bootstrap是一个前端ui框架,它把我们网页开发常用的功能都写好了,我们使用它可以像搭积木一样的轻松的开发网站,不过现在都流行前后端分析了,而且layui也比较好用,个人觉得无论哪个ui框架,我...
- BootStrap简介及应用要点
-
BootStrap简介BootStrap是基于HTML、CSS和JavaScript的框架,使你只需要写简单的代码就可以很快的搭建一个还不错的前端框架,他是后端程序员的福音,使它们只需要专注业务逻辑,...
- 如何在Bootstrap Studio中使用图标字体?
-
BootstrapStudioforMac是一款网站设计制作工具,图标字体类似于普通的Web字体,但是它们包含矢量形状,而不是字母和数字。那么如何在BootstrapStudio中使用图标字体...
- Bootstrap5.0-全球流行的前端开源UI工具包迎来了大版本更新
-
Bootstrap5.0正式发布了,带来了很多亮点,还学得动吗?Bootstrap介绍...
- BootstrapBlazor 模板适配移动设备使用笔记
-
项目模板BootstrapBlazorApp模板为了方便大家利用这套组件快速搭建项目,作者制作了项目模板(ProjectTemplates),使用dotnetnew命令行模式,使用步骤...
- bootstrap的tab标签页的使用
-
标签tab页在,当前的web中应用十分广泛,君不见,在博客的右侧出现的最新文章和随机文章中有它的身影,在大型门户网站中也有它的身影,可以说其无处不在的刷着存在感。既然其如此嚣张的存在,我们没有理由不应...
- 使用 Bootstrap 的最简单方法 - 让你的 HTML 看起来赏心悦目
-
什么是BootstrapBootstrap是一个免费的开源CSS框架,使得前端Web开发变得更加简单。...
- Bootstrap-table 使用总结
-
一、什么是Bootstrap-table?在业务系统开发中,对表格记录的查询、分页、排序等处理是非常常见的,在Web开发中,可以采用很多功能强大的插件来满足要求,且能极大的提高开发效率,本随笔介绍这...
- 建议收藏:哪些电子发票有XML格式?
-
报销时,财务要求提供发票XML格式。但不是所有的电子发票都有哦,目前只有数电发票(全面数字化的电子发票)有XML格式!目前的数电发票有下面这几大类:1、电子发票(增值税专用发票):适用于增值税一般纳税...
- Mybatis中mapper的xml解析详解
-
上一篇文章分析了mapper注解关键类MapperAnnotationBuilder,今天来看mapper的项目了解析关键类XMLMapperBuilder。基础介绍回顾下之前是在分析configur...
- word修改文中任意一处文字,其他地方相同的内容自动修改
-
我们工作写方案处理word的时候,经常会遇到这么一种情况,即文中存在多处相同的文字内容,可能是词语,也可能是段落。当我们修改了其中一处后,其他地方还得手动修改,十分不便。今天给大家分享一下,在word...
- 第9天 | 鸿蒙App开发实战,XML创建布局,共性很重要
-
XML声明布局的方式更加简便直观,是开发App的核心内容之一,咱们完全有必要搞清楚。每一个Component和ComponentContainer对象大部分属性都支持在XML中进行设置,它们有各自的X...
- 可扩展标记语言格式XML
-
1,XML(eXtensibleMarkupLanguage):指可扩展标记语言,一种数据表示格式,被设计用来传输和存储数据,不用于表现和展示数据。2,XML和基于XML的语言的整个结构是...
- 比较一下JSON与XML两种数据格式?
-
JSON(JavaScriptObjectNotation)和XML(eXtensibleMarkupLanguage)是在日常开发中比较常用的两种数据格式,它们主要的作用就是用来进行数据的传...
- PROFINET工业以太网教程(16)-GSDML文件详解
-
前面的文章(PROFINET工业以太网教程(10)——GSD文件)我们介绍过GSD文件,它的全称是“GeneralStationDescription”,中文翻译为“通用站描述文件”。GSD文件的...
- 一周热门
- 最近发表
- 标签列表
-
- grid 设置 (58)
- 移位运算 (48)
- not specified (45)
- patch补丁 (31)
- 导航栏 (58)
- context xml (46)
- scroll (43)
- dedecms模版 (53)
- c 视频教程下载 (33)
- listview排序 (33)
- firebug 使用 (31)
- characterencodingfilter (33)
- getmonth (34)
- hibernate教程 (31)
- label换行 (33)
- curlpost (31)
- android studio 3 0 (34)
- android应用开发 (31)
- html转js (35)
- 索引的作用 (33)
- checkedlistbox (34)
- localhost 8080 (32)
- 多态 (32)
- xmlhttp (35)
- mysql更改密码 (34)