一、测试类

  public class Main {
public static void main(String[] args) {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:app-${user}.xml");
Person person = applicationContext.getBean(Person.class);
System.out.println(person.getName());
}
}

同时添加jvm参数-Duser=test

二、app-test.xml文件

<beans>
<bean id="person" class="xml.Person">
<property value="张三" name="name"></property>
</bean>
</beans>

三、源码跟踪

public ClassPathXmlApplicationContext(String configLocation) throws BeansException {
this(new String[] {configLocation}, true, null);
}

创建ClassPathXmlApplicationContext从xml位置加载Bean定义。

public ClassPathXmlApplicationContext(
String[] configLocations, boolean refresh, @Nullable ApplicationContext parent)
throws BeansException {
super(parent); // 初始化父类
setConfigLocations(configLocations); // 设置xml文件位置
if (refresh) {
refresh(); // 刷新容器
}
}

从super(parent);进去

public AbstractApplicationContext(@Nullable ApplicationContext parent) {
this();
setParent(parent);
} @Override
public void setParent(@Nullable ApplicationContext parent) {
this.parent = parent;
if (parent != null) {
Environment parentEnvironment = parent.getEnvironment();
if (parentEnvironment instanceof ConfigurableEnvironment) {
getEnvironment().merge((ConfigurableEnvironment) parentEnvironment); // 与父类的Environment对象合并
}
}
} 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(); // 解析xml文件的路径,xml文件路径可能存在${}的情况,需要解析替换
}
}
else {
this.configLocations = null;
}
} protected String resolvePath(String path) {
return getEnvironment().resolveRequiredPlaceholders(path); // 解析${...}并替换
} @Override
public ConfigurableEnvironment getEnvironment() {
if (this.environment == null) {
this.environment = createEnvironment();
}
return this.environment;
} protected ConfigurableEnvironment createEnvironment() {
return new StandardEnvironment();
}

查看StandardEnvironment的父类AbstractEnvironment构造函数

    public AbstractEnvironment() {
this(new MutablePropertySources());
} protected AbstractEnvironment(MutablePropertySources propertySources) {
this.propertySources = propertySources;
this.propertyResolver = createPropertyResolver(propertySources);
customizePropertySources(propertySources);
} protected void customizePropertySources(MutablePropertySources propertySources) {
}

StandardEnvironment的customizePropertySources方法

    	@Override
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()));
}

AbstractEnvironment类

    @Override
@SuppressWarnings({"rawtypes", "unchecked"})
public Map<String, Object> getSystemProperties() {
try {
return (Map) System.getProperties(); // 获取JVM属性
}
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;
}
}
};
}
} @Override
@SuppressWarnings({"rawtypes", "unchecked"})
public Map<String, Object> 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;
}
}
};
}
}

resolveRequiredPlaceholders

     //AbstractEnvironment
@Override
public String resolveRequiredPlaceholders(String text) throws IllegalArgumentException {
return this.propertyResolver.resolveRequiredPlaceholders(text); \\ propertyResolver是PropertySourcesPropertyResolver
}

在创建StandardEnvironment对象时

    public AbstractEnvironment() {
this(new MutablePropertySources());
} protected AbstractEnvironment(MutablePropertySources propertySources) {
this.propertySources = propertySources;
this.propertyResolver = createPropertyResolver(propertySources);
customizePropertySources(propertySources);
} protected ConfigurablePropertyResolver createPropertyResolver(MutablePropertySources propertySources) {
return new PropertySourcesPropertyResolver(propertySources);
}

PropertySourcesPropertyResolver的父类AbstractPropertyResolver的方法resolveRequiredPlaceholders

    @Override
public String resolveRequiredPlaceholders(String text) throws IllegalArgumentException {
if (this.strictHelper == null) {
this.strictHelper = createPlaceholderHelper(false);
}
return doResolvePlaceholders(text, this.strictHelper);
} private String doResolvePlaceholders(String text, PropertyPlaceholderHelper helper) {
return helper.replacePlaceholders(text, this::getPropertyAsRawString);
} public String replacePlaceholders(String value, PlaceholderResolver placeholderResolver) {
Assert.notNull(value, "'value' must not be null");
return parseStringValue(value, placeholderResolver, null);
} protected String parseStringValue(
String value, PlaceholderResolver placeholderResolver, @Nullable Set<String> visitedPlaceholders) { int startIndex = value.indexOf(this.placeholderPrefix); //placeholderPrefix = "${"; 查找前缀位置
if (startIndex == -1) {
return value;
} StringBuilder result = new StringBuilder(value);
while (startIndex != -1) {
int endIndex = findPlaceholderEndIndex(result, startIndex); // 从startIndex开始在result查找placeholderSuffix的位置
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");
}
// Recursive invocation, parsing placeholders contained in the placeholder key.
placeholder = parseStringValue(placeholder, placeholderResolver, visitedPlaceholders); //递归调用parseStringValue解析placeholder,${}里面可能存在${}
// Now obtain the value for the fully resolved key...
String propVal = placeholderResolver.resolvePlaceholder(placeholder); //通过系统属性解析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) {
// Recursive invocation, parsing placeholders contained in the
// previously resolved placeholder value.
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) {
// Proceed with unprocessed value.
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();
} private int findPlaceholderEndIndex(CharSequence buf, int startIndex) {
int index = startIndex + this.placeholderPrefix.length();
int withinNestedPlaceholder = 0;
while (index < buf.length()) {
if (StringUtils.substringMatch(buf, index, this.placeholderSuffix)) { // placeholderSuffix = "}"
if (withinNestedPlaceholder > 0) {
withinNestedPlaceholder--;
index = index + this.placeholderSuffix.length();
}
else {
return index;
}
}
else if (StringUtils.substringMatch(buf, index, this.simplePrefix)) {
withinNestedPlaceholder++;
index = index + this.simplePrefix.length();
}
else {
index++;
}
}
return -1;
}

Spring源码-入门的更多相关文章

  1. Spring源码入门——DefaultBeanNameGenerator解析 转发 https://www.cnblogs.com/jason0529/p/5272265.html

    Spring源码入门——DefaultBeanNameGenerator解析   我们知道在spring中每个bean都要有一个id或者name标示每个唯一的bean,在xml中定义一个bean可以指 ...

  2. Spring源码入门——DefaultBeanNameGenerator解析

    我们知道在spring中每个bean都要有一个id或者name标示每个唯一的bean,在xml中定义一个bean可以指定其id和name值,但那些没有指定的,或者注解的spring的beanname怎 ...

  3. Spring源码入门——XmlBeanDefinitionReader解析

    接上篇[] ,我们看到BeanDefinitionReader解决的是从资源文件(xml,propert)到BeanDefinition集合的过程.所以BeanDefinitionReader接口有两 ...

  4. Spring源码入门——AnnotationBeanNameGenerator解析

    ---恢复内容开始--- 接上篇,上篇解析了DefaultBeanGenerator生成bean name的过程(http://www.cnblogs.com/jason0529/p/5272265. ...

  5. 从零开始学spring源码之xml解析(一):入门

    谈到spring,首先想到的肯定是ioc,DI依赖注入,aop,但是其实很多人只是知道这些是spring核心概念,甚至不知道这些代表了什么意思,,作为一个java程序员,怎么能说自己对号称改变了jav ...

  6. spring源码:学习线索(li)

    一.spring xml配置(不包括AOP,主要了解在初始化及实例化过程中spring配置文件中每项内容的具体实现过程,从根本上掌握spring) <bean>的名字 &,alia ...

  7. 阅读spring源码

    读Spring源码之前,你要先清楚,为什么你要用Spring... Spring最基本的功能是做为管理bean的容器,所以我以为应该先从org.springframework.context包了解咯, ...

  8. spring源码:学习线索

    一.spring xml配置(不包括AOP,主要了解在初始化及实例化过程中spring配置文件中每项内容的具体实现过程,从根本上掌握spring) <bean>的名字 &,alia ...

  9. spring 源码解析

    1. [文件] spring源码.txt ~ 15B     下载(167) ? 1 springн┤┬вио╬Ш: 2. [文件] spring源码分析之AOP.txt ~ 15KB     下载( ...

随机推荐

  1. CabloyJS微信模块、企业微信模块已出齐

    前言 当Cabloy-企业微信模块完成时,加上之前已完成的Cabloy-微信模块,关于在CabloyJS中与微信/企业微信对接的任务已经完成了.这些模块的目标就是,只需填入各类服务的参数,就可以直接进 ...

  2. vue-cli2.x配置build命令构建测试包&正式包

    项目开发中常分为开发环境.测试环境.正式环境 通过vue-cli或者@vue/cli脚手架搭建的项目默认提供了开发环境和正式环境的配置.可通过js获取当前域名或其他信息来判断当前为测试环境还是正式环境 ...

  3. Oracle账户被锁(the account is locked)

    问题: 安装好Oracle之后用scott登录报错:ERROR:ORA-28000:the account is locked 解决方案: Win+R打开命令行输入:sqlplus 使用system账 ...

  4. 循序渐进 Redis 分布式锁(以及何时不用它)

    场景 假设我们有个批处理服务,实现逻辑大致是这样的: 用户在管理后台向批处理服务投递任务: 批处理服务将该任务写入数据库,立即返回: 批处理服务有启动单独线程定时从数据库获取一批未处理(或处理失败)的 ...

  5. Docker部署jar包运行

    1.上传jar包到服务器 2.在该目录下创建Dockerfile 文件 vi Dockerfile 3.然后将下面的内容复制到Dockerfile文件中 FROM java:8 MAINTAINER ...

  6. 零基础学Java(4)字符串

    字符串 从概念上讲,Java字符串就是Unicode字符序列.例如,字符串"Java\u2122"由5个Unicode字符J.a.v.a和组成.Java没有内置的字符串类型,而是在 ...

  7. .Net下极限生产力之efcore分表分库全自动化迁移CodeFirst

    .Net下极限生产力之分表分库全自动化Migrations Code-First ## 介绍 本文ShardinfCore版本x.6.x.x+ 本期主角: - [`ShardingCore`](htt ...

  8. 【docker专栏3】docker基础概念-容器、镜像以及引擎组成部分

    一.docker镜像与容器 docker镜像是一个可执行的静态独立软件包,包含打包程序代码和软件运行环境等文件.如:代码.运行时库.环境变量和配置文件等都包含在其中.容器是镜像的运行时状态(镜像中的软 ...

  9. 攻防世界MISC进阶区 52-55

    52.Excaliflag 得到一张png,扔进stegsolve中查看,找到flag 53.Just-No-One 得到一个exe,运行后居然是一个安装程序,看了一下没什么问题,扔进ida pro中 ...

  10. 在矩池云使用Disco Diffusion生成AI艺术图

    在 Disco Diffusion 官方说明的第一段,其对自身是这样定义: AI Image generating technique called CLIP-Guided Diffusion.DD ...