博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Spring源码 04 IOC XML方式
阅读量:37194 次
发布时间:2020-08-01

本文共 15704 字,大约阅读时间需要 52 分钟。

参考源

《Spring源码深度解析(第2版)》

版本

本文章基于 Spring 5.3.15


Spring IOC 主要有两种实现方式:XML注解

这里分析 XML 方式。

ClassPathXmlApplicationContext("applicationContext.xml")

配置文件

首先看解析的对象:配置文件

Spring 的配置文件是一个典型的 XML 文件,其中的标签名称标签属性都是约定好的,在没有自定义前只能按照约定的格式编写。

约束方式

这里先介绍 XML 文件的两种约束方式:DTDXSD

DTD

DTD(Document Type Definition)文档类型定义

一种 XML 约束模式语言,是 XML 文件的验证机制,属于 XML 文件组成的一部分

一种保证 XML 文档格式正确的有效方法,可以通过比较 XML 文档和 DTD 文件来看文档是否符合规范,元素和标签使用是否正确。

DTD 文档内容

  • 元素的定义规则
  • 元素间关系的定义规则
  • 元素可使用的属性
  • 可使用的实体或符号规则

要使用 DTD 验证模式的时候需要在 XML 文件的头部声明,例如在 Spring 中使用 DTD 声明方式

老版本的 Spring 使用 DTD,新版本的 Spring 都使用 XSD 了。

XSD

XSD(XML Schemas Definition)XML描述定义

描述 XML 文档的结构,验证 XML 文档是否符合其要求。

指定 XML 文档所允许的结构和内容,检查 XML 文档是否有效。

本身是 XML 文档,符合 XML 语法结构,可以用通用的 XML 解析器解析。

对 XML 文档进行检验,需要声明名称空间(xmlns)和文档存储位置(xsi:schemaLocation)。

其中 xsi:schemaLocation 指向一个网络地址

由于网络不可靠,且经常会脱网开发,Spring 会通过 resources/META-INF/spring.schemas 定义本地路径。

比如上面的配置文件映射的本地路径:

http\://www.springframework.org/schema/beans/spring-beans.xsd=org/springframework/beans/factory/xml/spring-beans.xsd

两个路径下的内容是完全一致的。

接下来开始分析 ClassPathXmlApplicationContext("applicationContext.xml")

由于 Spring 源码层级十分复杂,约定如下规则

  • 数字 类名:数字代表该类出现的顺序。
  • 类数字-数字 方法注释:数字代表该方法在类中执行的层级。

1 ClassPathXmlApplicationContext

由于其父类 AbstractApplicationContext 存在静态代码块,先进入父类的静态代码块。

2 AbstractApplicationContext

2-1 静态代码块

进入 ClassPathXmlApplicationContext 的构造方法,会先进入 AbstractApplicationContext 的静态代码块。

static {    /**     * 优先加载上下文关闭事件来防止奇怪的类加载问题     * WebLogic 8.1 在应用程序关闭的时候出现的 BUG     */    ContextClosedEvent.class.getName();}

这里是针对 WebLogic 8.1 的特殊处理,与主体逻辑不关,不用过于关注。

1 ClassPathXmlApplicationContext

public  ClassPathXmlApplicationContext(String configLocation) throws BeansException {   this(new String[] {configLocation}, true, null);}
public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, @Nullable ApplicationContext parent) throws BeansException {    // 调用父类构造方法,进行相关的对象创建等操作,包含属性的赋值操作    super(parent);    // 设置配置文件路径    setConfigLocations(configLocations);    if (refresh) {        // 刷新        refresh();    }}

1-1 父类构造方法

super(parent)
public AbstractXmlApplicationContext(@Nullable ApplicationContext parent) {    super(parent);}
public AbstractRefreshableConfigApplicationContext(@Nullable ApplicationContext parent) {    super(parent);}
public AbstractRefreshableApplicationContext(@Nullable ApplicationContext parent) {    super(parent);}
public AbstractApplicationContext(@Nullable ApplicationContext parent) {    this();    // 设置父容器    setParent(parent);}

2 AbstractApplicationContext

this()
public AbstractApplicationContext() {    // 创建资源模式处理器    this.resourcePatternResolver = getResourcePatternResolver();}

2-2 创建资源模式处理器

protected ResourcePatternResolver getResourcePatternResolver() {    // 创建一个资源模式解析器,用来解析 XML 配置文件    return new PathMatchingResourcePatternResolver(this);}

3 PathMatchingResourcePatternResolver

PathMatchingResourcePatternResolver(this)
public PathMatchingResourcePatternResolver(ResourceLoader resourceLoader) {    Assert.notNull(resourceLoader, "ResourceLoader must not be null");    this.resourceLoader = resourceLoader;}

2 AbstractApplicationContext

2-1 设置父容器

setParent(parent)
public void setParent(@Nullable ApplicationContext parent) {    this.parent = parent;    if (parent != null) {        Environment parentEnvironment = parent.getEnvironment();        if (parentEnvironment instanceof ConfigurableEnvironment) {            getEnvironment().merge((ConfigurableEnvironment) parentEnvironment);        }    }}

if (parent != null) 由于 parent 没有传,执行结束。

1 ClassPathXmlApplicationContext

1-1 设置配置文件路径

setConfigLocations(configLocations)

由于该类没有定义该方法,调用其父类 AbstractRefreshableConfigApplicationContext 的该方法。

4 AbstractRefreshableConfigApplicationContext

public void setConfigLocations(@Nullable String... locations) {    if (locations != null) {        Assert.noNullElements(locations, "Config locations must not be null");        this.configLocations = new String[locations.length];        for (int i = 0; i < locations.length; i++) {            // 解析给定路径            this.configLocations[i] = resolvePath(locations[i]).trim();        }    }    else {        this.configLocations = null;    }}

4-1 解析给定路径

resolvePath(locations[i])
protected String resolvePath(String path) {    // 获取环境信息    // 解析所需的占位符    return getEnvironment().resolveRequiredPlaceholders(path);}

4-2 获取环境信息

getEnvironment()
public ConfigurableEnvironment getEnvironment() {    if (this.environment == null) {        // 创建环境对象        this.environment = createEnvironment();    }    return this.environment;}

4-3 创建环境对象

createEnvironment()
protected ConfigurableEnvironment createEnvironment() {    return new StandardEnvironment();}

5 StandardEnvironment

public StandardEnvironment() {}

由于继承关系,再调用 AbstractEnvironment 的构造方法。

6 AbstractEnvironment

public AbstractEnvironment() {    this(new MutablePropertySources());}
protected AbstractEnvironment(MutablePropertySources propertySources) {    this.propertySources = propertySources;    // 创建属性解析器    this.propertyResolver = createPropertyResolver(propertySources);    // 定制化属性资源    customizePropertySources(propertySources);}

6-1 创建属性解析器

createPropertyResolver(propertySources)
protected ConfigurablePropertyResolver createPropertyResolver(MutablePropertySources propertySources) {    return new PropertySourcesPropertyResolver(propertySources);}

7 PropertySourcesPropertyResolver

public PropertySourcesPropertyResolver(@Nullable PropertySources propertySources) {    this.propertySources = propertySources;}

6 AbstractEnvironment

6-1 定制化属性资源

customizePropertySources(propertySources)

由于子类重写了该方法,会调用子类方法。

5 StandardEnvironment

protected void customizePropertySources(MutablePropertySources propertySources) {    // 获取系统属性    propertySources.addLast(new PropertiesPropertySource(SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME, getSystemProperties()));    // 获取系统环境    propertySources.addLast(new SystemEnvironmentPropertySource(SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME, getSystemEnvironment()));}

5-1 获取系统属性

getSystemProperties()
public Map
getSystemProperties() { try { return (Map) System.getProperties(); } catch (AccessControlException ex) { return (Map) new ReadOnlySystemAttributesMap() { @Override @Nullable protected String getSystemAttribute(String attributeName) { try { return System.getProperty(attributeName); } catch (AccessControlException ex) { if (logger.isInfoEnabled()) { logger.info("Caught AccessControlException when accessing system property '" + attributeName + "'; its value will be returned [null]. Reason: " + ex.getMessage()); } return null; } } }; }}

5-1 获取系统环境

getSystemEnvironment()
public Map
getSystemEnvironment() { if (suppressGetenvAccess()) { return Collections.emptyMap(); } try { return (Map) System.getenv(); } catch (AccessControlException ex) { return (Map) new ReadOnlySystemAttributesMap() { @Override @Nullable protected String getSystemAttribute(String attributeName) { try { return System.getenv(attributeName); } catch (AccessControlException ex) { if (logger.isInfoEnabled()) { logger.info("Caught AccessControlException when accessing system environment variable '" + attributeName + "'; its value will be returned [null]. Reason: " + ex.getMessage()); } return null; } } }; }}

4 AbstractRefreshableConfigApplicationContext

4-2 解析所需的占位符

resolveRequiredPlaceholders(path)

由于前面的 getEnvironment() 返回值为 ConfigurableEnvironment 接口,AbstractEnvironment 实现了该接口,所以跳转。

6 AbstractEnvironment

public String resolveRequiredPlaceholders(String text) throws IllegalArgumentException {    // 解析所需的占位符    return this.propertyResolver.resolveRequiredPlaceholders(text);}

由于 this.propertyResolver 的对象为 ConfigurablePropertyResolver,其由 AbstractPropertyResolver 实现,所以跳转。

7 AbstractPropertyResolver

public String resolveRequiredPlaceholders(String text) throws IllegalArgumentException {    if (this.strictHelper == null) {        // 创建占位符        this.strictHelper = createPlaceholderHelper(false);    }    // 解决占位符    return doResolvePlaceholders(text, this.strictHelper);}

7-1 创建占位符

createPlaceholderHelper(false)
private PropertyPlaceholderHelper createPlaceholderHelper(boolean ignoreUnresolvablePlaceholders) {   	return new PropertyPlaceholderHelper(this.placeholderPrefix, this.placeholderSuffix, this.valueSeparator, ignoreUnresolvablePlaceholders);}

8 PropertyPlaceholderHelper

public PropertyPlaceholderHelper(String placeholderPrefix, String placeholderSuffix, @Nullable String valueSeparator, boolean ignoreUnresolvablePlaceholders) {    Assert.notNull(placeholderPrefix, "'placeholderPrefix' must not be null");    Assert.notNull(placeholderSuffix, "'placeholderSuffix' must not be null");    this.placeholderPrefix = placeholderPrefix;    this.placeholderSuffix = placeholderSuffix;    String simplePrefixForSuffix = wellKnownSimplePrefixes.get(this.placeholderSuffix);    if (simplePrefixForSuffix != null && this.placeholderPrefix.endsWith(simplePrefixForSuffix)) {        this.simplePrefix = simplePrefixForSuffix;    } else {        this.simplePrefix = this.placeholderPrefix;    }    this.valueSeparator = valueSeparator;    this.ignoreUnresolvablePlaceholders = ignoreUnresolvablePlaceholders;}

7 AbstractPropertyResolver

7-1 解决占位符

doResolvePlaceholders(text, this.strictHelper)
private String doResolvePlaceholders(String text, PropertyPlaceholderHelper helper) {   	// 替换占位符    return helper.replacePlaceholders(text, this::getPropertyAsRawString);}

7-2 替换占位符

replacePlaceholders(text, this::getPropertyAsRawString)
public String replacePlaceholders(String value, PlaceholderResolver placeholderResolver) {	Assert.notNull(value, "'value' must not be null");   	// 解析字符串值    return parseStringValue(value, placeholderResolver, null);}

7-3 解析字符串值

protected String parseStringValue(String value, PlaceholderResolver placeholderResolver, @Nullable Set
visitedPlaceholders) { // 获取前缀符所在位置 int startIndex = value.indexOf(this.placeholderPrefix); if (startIndex == -1) { return value; } StringBuilder result = new StringBuilder(value); while (startIndex != -1) { // 获取后缀符所在位置 int endIndex = findPlaceholderEndIndex(result, startIndex); if (endIndex != -1) { // 获取前缀符和后缀符中间的值 String placeholder = result.substring(startIndex + this.placeholderPrefix.length(), endIndex); String originalPlaceholder = placeholder; if (visitedPlaceholders == null) { visitedPlaceholders = new HashSet<>(4); } if (!visitedPlaceholders.add(originalPlaceholder)) { throw new IllegalArgumentException("Circular placeholder reference '" + originalPlaceholder + "' in property definitions"); } // 递归调用,解析占位符键中包含的占位符 placeholder = parseStringValue(placeholder, placeholderResolver, visitedPlaceholders); // 获取完全解析后的值 String propVal = placeholderResolver.resolvePlaceholder(placeholder); if (propVal == null && this.valueSeparator != null) { int separatorIndex = placeholder.indexOf(this.valueSeparator); if (separatorIndex != -1) { String actualPlaceholder = placeholder.substring(0, separatorIndex); String defaultValue = placeholder.substring(separatorIndex + this.valueSeparator.length()); propVal = placeholderResolver.resolvePlaceholder(actualPlaceholder); if (propVal == null) { propVal = defaultValue; } } } if (propVal != null) { // 递归调用,处理全部的占位符 propVal = parseStringValue(propVal, placeholderResolver, visitedPlaceholders); result.replace(startIndex, endIndex + this.placeholderSuffix.length(), propVal); if (logger.isTraceEnabled()) { logger.trace("Resolved placeholder '" + placeholder + "'"); } startIndex = result.indexOf(this.placeholderPrefix, startIndex + propVal.length()); } else if (this.ignoreUnresolvablePlaceholders) { // 继续处理剩余的值 startIndex = result.indexOf(this.placeholderPrefix, endIndex + this.placeholderSuffix.length()); } else { throw new IllegalArgumentException("Could not resolve placeholder '" + placeholder + "'" + " in value \"" + value + "\""); } visitedPlaceholders.remove(originalPlaceholder); } else { startIndex = -1; } } return result.toString();}
if (startIndex == -1) {    return value;}

由于配置文件名称没有前缀符,执行结束。

1 ClassPathXmlApplicationContext

1-1 刷新

2 AbstractApplicationContext

refresh()
public void refresh() throws BeansException, IllegalStateException {   // 同步监视器   synchronized (this.startupShutdownMonitor) {      StartupStep contextRefresh = this.applicationStartup.start("spring.context.refresh");      /*      1 准备刷新的上下文环境。例如对系统属性或者环境变量进行准备及验证      设置容器的启动时间      设置关闭状态为 false      设置活跃状态为 true      获取 Environment 对象,并加载当前系统的属性值到 Environment 对象中并进行验证      准备监听器和事件的集合对象,默认为空的集合       */      prepareRefresh();      /*      2 初始化 BeanFactory,并进行 XML 文件读取      创建容器对象:DefaultListableBeanFactory      加载 XML 配置文件的属性值到当前工厂中,最重要的就是 BeanDefinition       */      ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();      /*      3 对 BeanFactory 进行各种功能填充      比如 @Qualifier 与 @Autowired 就是在这一步骤中增加的支持       */      prepareBeanFactory(beanFactory);      try {         /*         4 定义 Bean 工厂的增强器,子类覆盖方法做额外的处理(此处我们自己一般不做任何扩展工作,但是可以查看 web 中的代码是有具体实现的)          */         postProcessBeanFactory(beanFactory);         StartupStep beanPostProcess = this.applicationStartup.start("spring.context.beans.post-process");         /*         5 执行 Bean 工厂的增强器,激活各种 beanFactory 处理器          */         invokeBeanFactoryPostProcessors(beanFactory);         /*         6 注册 Bean 增强器。注册拦截 Bean 创建的 Bean 处理器,这里只是注册,真正的调用是在 getBean 时候          */         registerBeanPostProcessors(beanFactory);         beanPostProcess.end();         /*         7 为上下文初始化 message 源,即不同语言的消息体,国际化处理          */         initMessageSource();         /*         8 初始化应用消息广播器,并放入 "applicationEventMulticaster" bean 中          */         initApplicationEventMulticaster();         /*         9 特定刷新。初始化其他的 bean,留给子类扩展          */         onRefresh();         /*         10 注册监听器。在所有注册的 bean 中查找 listen bean,注册到消息广播器中          */         registerListeners();         /*         11 初始化剩下的单实例(非懒加载的)          */         finishBeanFactoryInitialization(beanFactory);         /*         12 完成刷新过程,通知生命周期处理器 lifecycleProcessor 刷新过程,同时发出 ContextRefreshEvent 通知别人          */         finishRefresh();      } catch (BeansException ex) {         if (logger.isWarnEnabled()) {            logger.warn("Exception encountered during context initialization - " + "cancelling refresh attempt: " + ex);         }         // 为防止bean资源占用,在异常处理中,销毁已经在前面过程中生成的单件bean         destroyBeans();         // 重置active标志         cancelRefresh(ex);         throw ex;      } finally {         /*         13 清空缓存          */         resetCommonCaches();         contextRefresh.end();      }   }}

AbstractApplicationContext 中的 refresh() 是整个 IOC 的核心。

后续会对其中的 13 个主要方法做详细解析。

转载地址:http://vupwwy.baihongyu.com/

你可能感兴趣的文章
WinDbg安装与使用
查看>>
推荐阅读的多核编程技术书籍
查看>>
维基百科上的算法和数据结构链接很强大
查看>>
选择排序
查看>>
PHP session回收机制
查看>>
最新的全球编程语言,操作系统,web服务器等使用率分析报告
查看>>
用C语言写PHP扩展
查看>>
PHP Extension programming
查看>>
海量数据处理
查看>>
PHP防止注入攻击
查看>>
多路IO复用模型 select epoll 等
查看>>
Linux Epoll介绍和程序实例
查看>>
output_buffering详细介绍
查看>>
php缓冲 output_buffering和ob_start
查看>>
php error_reporting 详解
查看>>
剖析PHP中的输出缓冲
查看>>
HTTP响应头不缓存
查看>>
phpize
查看>>
PHP安装eAccelerator
查看>>
PHP新的垃圾回收机制:Zend GC详解
查看>>