spring4.1.8初始化源码学习三部曲之二:setConfigLocations方法

本文深入剖析了Spring框架中ClassPathXmlApplicationContext.setConfigLocations方法的工作原理,包括如何创建环境对象ConfigurableEnvironment及处理配置文件路径中的占位符。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

转载自: https://blog.youkuaiyun.com/boling_cavalry/article/details/80958832

本章是学习spring4.1.8初始化源码的第二篇,前一章《spring4.1.8初始化源码学习三部曲之一:AbstractApplicationContext构造方法》对AbstractApplicationContext的初始化做了分析,本章我们聚焦ClassPathXmlApplicationContext.setConfigLocations方法;
整体概括

本章会涉及到多个类的细节,所以先从整体上概括AbstractRefreshableConfigApplicationContext.setConfigLocations方法的主要功能,后面的细节都是基于这些总结展开的:
1. setConfigLocations主要工作有两个:创建环境对象ConfigurableEnvironment 、处理ClassPathXmlApplicationContext传入的字符串中的占位符;
2. 环境对象ConfigurableEnvironment中包含了当前JVM的profile配置信息、环境变量、 Java进程变量;
3. 处理占位符的关键是ConfigurableEnvironment、PropertyResolver、PropertyPlaceholderHelper之间的配合:
名称 作用
ConfigurableEnvironment 1.创建PropertyResolver;
2.向PropertyResolver提供环境变量、 Java进程变量
PropertyResolver 1.创建PropertyPlaceholderHelper;
2.定义占位符的前缀和后缀(placeholderPrefix、placeholderSuffix);
3.提供getPropertyAsRawString方法给PropertyPlaceholderHelper调用,用来获取指定key对应的环境变量;
PropertyPlaceholderHelper 1.找到字符串中的占位符;
2.调用PropertyResolver.getPropertyAsRawString方法,从环境变量中取出占位符对应的值
3.用环境变量的值替换占位符;

用思维导图来辅助:
这里写图片描述

对占位符的处理实战,请参考文章《windows下修改、编译、构建spring-framework4.1.8.RELEASE源码》,这里面用demo展示了占位符的替换;
展开详情

接下来去阅读setConfigLocations方法内部的细节代码:

跟踪该方法,找到是在类AbstractRefreshableConfigApplicationContext中实现的:

public void setConfigLocations(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;
}
}

  1. 从上述代码可以发现,本章我们要重点学习的是resolvePath(locations[i]),结合上一章demo中的入参,此处应该是方法resolvePath(“classpath:applicationContext.xml”);
  2. 跟踪到AbstractRefreshableConfigApplicationContext类,这个方法的目的是替换掉path字符串中的占位符${XXX}这样的内容:

protected String resolvePath(String path) {
return getEnironment().resolveRequiredPlaceholders(path);
}

  1. 先看getEnvironment()方法:

@Override
public ConfigurableEnvironment getEnvironment() {
if (this.environment == null) {
this.environment = createEnvironment();
}
return this.environment;
}

  1. 关于ConfigurableEnvironment接口,我们先来看看他的声明方法以及继承关系:
    这里写图片描述
    从上图可见,ConfigurableEnvironment接口有两个重要部分组成:Profile和Property;
    Profile是对测试、生产等不同环境下的bean配置,这里我们没有特别设置,所以用到的profile是AbstractEnvironment的defaultProfiles;
    接下来关于Property资源是如何产生的;

  2. 顺着调用一路看过去,发现最终会调用AbstractEnvironment类的构造方法:

public AbstractEnvironment() {
customizePropertySources(this.propertySources);
if (this.logger.isDebugEnabled()) {
this.logger.debug(format(
“Initialized %s with PropertySources %s”, getClass().getSimpleName(), this.propertySources));
}
}

  1. 上面的customizePropertySources是在StandardEnvironment类中实现的,如下:

@Override
protected void customizePropertySources(MutablePropertySources propertySources) {
propertySources.addLast(new MapPropertySource(SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME, getSystemProperties()));
propertySources.addLast(new SystemEnvironmentPropertySource(SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME, getSystemEnvironment()));
}

上述代码中,可以将propertySources对象理解成一个容器(其对象内部核心成员propertySourceList是个CopyOnWriteArrayList实例);
首先向propertySources添加一组属性,来自Java进程变量(getSystemProperties()内是System.getProperties()方法);
接着向propertySources再添加一组属性,来自系统环境变量(getSystemEnvironment()内是System.getenv()方法);
getSystemProperties和getSystemEnvironment方法中有个相同的细节需要注意,在获取进程变量或者系统环境变量的时候,都有可能因为安全限制抛出异常,这时候就返回一个ReadOnlySystemAttributesMap的实现类,外部调用get方法的时候,再去尝试获取进程变量或者系统环境变量对应的值,取不到则返回null,代码如下:

public Map

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值