关于properties:

在spring框架中properties为Environment对象重要组成部分,

springboot有如下几种种方式注入(优先级从高到低):

1、命令行
java -jar ***.jar --spring.profiles.active=test &
2、java系统参数
System.getProperties()
3.操作系统环境变量。
环境变量。。不解释
4.从 java:comp/env 得到的 JNDI 属性。
不懂是啥,埋坑。
5.通过 RandomValuePropertySource 生成的“random.*”属性。
springboot中随机端口功能类似的东西吧。
6.应用 Jar 文件之外的属性文件(spring.config.location参数)
java -jar myproject.jar spring.config.location=classpath:/default.properties
7.应用 Jar 文件内部的属性文件
8.通过@PropertySource
@PropertySource("classpath:sys.properties")
@Configuration
public class JavaDoopConfig { }
9.通过“SpringApplication.setDefaultProperties”声明的默认属性。

源码分析

1.SpringApplication.run方法中prepareEnvironment初始化

private ConfigurableEnvironment prepareEnvironment(
SpringApplicationRunListeners listeners,
ApplicationArguments applicationArguments) {
// 创建Environment对象
ConfigurableEnvironment environment = getOrCreateEnvironment();
//注入commonLine配置源,并提高有限级到最高。
configureEnvironment(environment, applicationArguments.getSourceArgs());
//事件监听,估计跟动态加载有关,太高端不分析了。
listeners.environmentPrepared(environment);
bindToSpringApplication(environment);
//自定义环境对象,这个也太高端,分析不了。
if (!this.isCustomEnvironment) {
environment = new EnvironmentConverter(getClassLoader())
.convertEnvironmentIfNecessary(environment, deduceEnvironmentClass());
}
//深入jar包了。
ConfigurationPropertySources.attach(environment);
return environment;
}
1.1 getOrCreateEnvironment()方法解析:初始化StandardServletEnvironment对象。
/**
* 根据不同springboot类型创建对应的Environment对象
**/
private ConfigurableEnvironment getOrCreateEnvironment() {
if (this.environment != null) {
return this.environment;
}
switch (this.webApplicationType) {
case SERVLET:
return new StandardServletEnvironment();
case REACTIVE:
return new StandardReactiveWebEnvironment();
default:
return new StandardEnvironment();
}
}
/**
* 初始化StandardServletEnvironments时,默认添加几种propertySources。
**/
@Override
protected void customizePropertySources(MutablePropertySources propertySources) {
//servlet上下文中的属性源
propertySources.addLast(new StubPropertySource(SERVLET_CONFIG_PROPERTY_SOURCE_NAME));
//servlet配置文件中的属性源
propertySources.addLast(new StubPropertySource(SERVLET_CONTEXT_PROPERTY_SOURCE_NAME));
//Jndi中配置的属性源
if (JndiLocatorDelegate.isDefaultJndiEnvironmentAvailable()) {
propertySources.addLast(new JndiPropertySource(JNDI_PROPERTY_SOURCE_NAME));
}
//调用父类方法
super.customizePropertySources(propertySources);
} /**
* 调用StandardEnvironment对象初始化,系统参数
**/
@Override
protected void customizePropertySources(MutablePropertySources propertySources) {
//设置java参数属性源
propertySources.addLast(new MapPropertySource(SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME, getSystemProperties()));
//环境变量属性源
propertySources.addLast(new SystemEnvironmentPropertySource(SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME, getSystemEnvironment()));
}

以上代码都是调用addLast方法,优先级最低。
所以优先级顺序:
1、servlet 上下文
2、servlet 配置文件
3、Jndi 属性源
4、java参数属性源。
5、环境变量属性源。

1.2:configureEnvironment方法解析:
protected void configureEnvironment(ConfigurableEnvironment environment,String[] args) {
//不懂
if (this.addConversionService) {
ConversionService conversionService = ApplicationConversionService
.getSharedInstance();
environment.setConversionService(
(ConfigurableConversionService) conversionService);
}
//配置加入命令参数配置源
configurePropertySources(environment, args);
configureProfiles(environment, args);
} protected void configurePropertySources(ConfigurableEnvironment environment,String[] args) {
MutablePropertySources sources = environment.getPropertySources();
if (this.defaultProperties != null && !this.defaultProperties.isEmpty()) {
sources.addLast(
new MapPropertySource("defaultProperties", this.defaultProperties));
}
if (this.addCommandLineProperties && args.length > 0) {
String name = CommandLinePropertySource.COMMAND_LINE_PROPERTY_SOURCE_NAME;
if (sources.contains(name)) {
PropertySource<?> source = sources.get(name);
CompositePropertySource composite = new CompositePropertySource(name);
composite.addPropertySource(new SimpleCommandLinePropertySource(
"springApplicationCommandLineArgs", args));
composite.addPropertySource(source);
sources.replace(name, composite);
}
//添加到最高优先级
else {
sources.addFirst(new SimpleCommandLinePropertySource(args));
}
}
}

以上代码都是调用addFirst方法,优先级最高。
所以优先级顺序:
1、commonLine 属性
2、servlet 上下文
3、servlet 配置文件
4、Jndi 属性源
5、java参数属性源。
6、环境变量属性源。

1.3:事件监听分析(mmp,看源码一步都不能省,鬼知道里面发生了啥)
发布ApplicationEnvironmentPreparedEvent事件被ConfigFileApplicationListener监听到。

/**
* 监听到事件后,处理方法
**/
private void onApplicationEnvironmentPreparedEvent(
ApplicationEnvironmentPreparedEvent event) {
//从spring.factories下获取所有的EnvironmentPostProcessor
// EnvironmentPostProcessor为springboot动态管理自定义配置源的接口
//默认3个(json转换啊,系统参数重载啊,vopc云服务相关的)
/**
* 还有就是ConfigFileApplicationListener 自身也实现可该接口
* 加载springboot相关配置源到容器中。
**/
List<EnvironmentPostProcessor> postProcessors = loadPostProcessors();
postProcessors.add(this);
AnnotationAwareOrderComparator.sort(postProcessors);
for (EnvironmentPostProcessor postProcessor : postProcessors) {
postProcessor.postProcessEnvironment(event.getEnvironment(),
event.getSpringApplication());
}
} /**
* RandomValuePropertySource 加入优先级
* 很重要,后面慢慢研究,今天只关注配置源
**/
public static void addToEnvironment(ConfigurableEnvironment environment) {
//加载环境变量优先级后面
environment.getPropertySources().addAfter(
StandardEnvironment.SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME,
new RandomValuePropertySource(RANDOM_PROPERTY_SOURCE_NAME));
logger.trace("RandomValuePropertySource add to Environment");
}
/**
* 然后调用了springboot读取配置的核心方法。
**/
public void load() {
this.profiles = new LinkedList<>();
this.processedProfiles = new LinkedList<>();
this.activatedProfiles = false;
this.loaded = new LinkedHashMap<>();
initializeProfiles();
while (!this.profiles.isEmpty()) {
Profile profile = this.profiles.poll();
if (profile != null && !profile.isDefaultProfile()) {
addProfileToEnvironment(profile.getName());
}
load(profile, this::getPositiveProfileFilter,
addToLoaded(MutablePropertySources::addLast, false));
this.processedProfiles.add(profile);
}
resetEnvironmentProfiles(this.processedProfiles);
load(null, this::getNegativeProfileFilter,
addToLoaded(MutablePropertySources::addFirst, true));
//上面各种嵌套逻辑,加载好配置后
addLoadedPropertySources();
} /**
* 依次加载配置文件到最后。
**/
private void addLoadedPropertySource(MutablePropertySources destination,
String lastAdded, PropertySource<?> source) {
if (lastAdded == null) {
if (destination.contains(DEFAULT_PROPERTIES)) {
destination.addBefore(DEFAULT_PROPERTIES, source);
}
else {
destination.addLast(source);
}
}
else {
destination.addAfter(lastAdded, source);
}
}

变更后所以优先级顺序:
1、commonLine 属性
2、servlet 上下文
3、servlet 配置文件
4、Jndi 属性源
5、java参数属性源。
6、环境变量属性源。
7、random属性源。
8、springboot 配置源(application-dev.yml 优先于application.yml)


 

springboot Properties加载顺序源码分析的更多相关文章

  1. Springboot 加载配置文件源码分析

    Springboot 加载配置文件源码分析 本文的分析是基于springboot 2.2.0.RELEASE. 本篇文章的相关源码位置:https://github.com/wbo112/blogde ...

  2. Springboot学习04-默认错误页面加载机制源码分析

    Springboot学习04-默认错误页面加载机制源码分析 前沿 希望通过本文的学习,对错误页面的加载机制有这更神的理解 正文 1-Springboot错误页面展示 2-Springboot默认错误处 ...

  3. ElasticSearch 启动时加载 Analyzer 源码分析

    ElasticSearch 启动时加载 Analyzer 源码分析 本文介绍 ElasticSearch启动时如何创建.加载Analyzer,主要的参考资料是Lucene中关于Analyzer官方文档 ...

  4. 微服务架构 | *2.3 Spring Cloud 启动及加载配置文件源码分析(以 Nacos 为例)

    目录 前言 1. Spring Cloud 什么时候加载配置文件 2. 准备 Environment 配置环境 2.1 配置 Environment 环境 SpringApplication.prep ...

  5. Spring Cloud Nacos实现动态配置加载的源码分析

    理解了上述Environment的基本原理后,如何从远程服务器上加载配置到Spring的Environment中. NacosPropertySourceLocator 顺着前面的分析思路,我们很自然 ...

  6. jQuery实现DOM加载方法源码分析

    传统的判断dom加载的方法 使用 dom0级 onload事件来进行触发所有浏览器都支持在最初是很流行的写法 我们都熟悉这种写法: window.onload=function(){ ... }  但 ...

  7. Spring boot加载REACTIVE源码分析

    一,加载REACTIVE相关自动配置 spring boot通过判断含org.springframework.web.reactive.DispatcherHandler字节文件就确定程序类型是REA ...

  8. spring启动component-scan类扫描加载过程---源码分析

    http://blog.csdn.net/xieyuooo/article/details/9089441#comments

  9. Spring加载流程源码分析03【refresh】

      前面两篇文章分析了super(this)和setConfigLocations(configLocations)的源代码,本文来分析下refresh的源码, Spring加载流程源码分析01[su ...

随机推荐

  1. css样式writing-mode垂直书写测试

    writing-mode:控制文字的属性方向,但是不是所有的浏览器都兼容,在网页上使用时,有的浏览器显示不出该样式.该文测试的是垂直书写:网上对于测试的属性值的解释是:tb-rl:上-下,右-左.对象 ...

  2. MySQL优化详解

    MySQL优化 MYSQL优化主要分为以下四大方面: 设计:存储引擎,字段类型,范式与逆范式 功能:索引,缓存,分区分表. 架构:主从复制,读写分离,负载均衡. 合理SQL:测试,经验. 一.存储引擎 ...

  3. 第5课.linux进阶命令

    1.find:查找符合条件的文件 格式: find 目录名 选项 查找条件 eg: find /work/001_linux_basic/dira/ -name "test1.txt&quo ...

  4. PHP curl模拟ip和来源进行访问

    PHP curl模拟ip和来源进行访问<pre> public function moniurlqingqiu() { $ch = curl_init(); $curlurl = &quo ...

  5. 带你一步一步搭建TypeScript环境

    今天继续来更新,本篇文章我们讲环境搭建,主要分享一些环境搭建的学习资源及安装步骤,解决一些安装时可能会出现的问题.下面就让我们一起进入学习第一步,搭建TypeScript环境:一. 环境搭建1.1. ...

  6. Spring 中的统一异常处理

    在具体的SSM项目开发中,由于Controller层为处于请求处理的最顶层,再往上就是框架代码的.因此,肯定需要在Controller捕获所有异常,并且做适当处理,返回给前端一个友好的错误码. 不过, ...

  7. 初始化一个React项目(TypeScript环境)

    React将由三部分组成,其中,Redux是应用状态管理服务,React-Router用于路由映射,React View用于显示界面. 我们使用Facebook推荐的create-react-app来 ...

  8. js 中加减乘除 比较精确的算法,js本身有些运算会出错,这里给出较精确的算法

    问题这样的: 37.5*5.5=206.08  (JS算出来是这样的一个结果,我四舍五入取两位小数) 我先怀疑是四舍五入的问题,就直接用JS算了一个结果为:206.08499999999998 怎么会 ...

  9. 手写PE结构解析工具

    PE格式是 Windows下最常用的可执行文件格式,理解PE文件格式不仅可以了解操作系统的加载流程,还可以更好的理解操作系统对进程和内存相关的管理知识,而有些技术必须建立在了解PE文件格式的基础上,如 ...

  10. Delphi XE10.1 引用计数(Delphi XE10.1 Berlin终于增加了对接口的Weak, UnSafe的支持)

    以往的Delphi版本,不支持接口的Weak,和UnSafe的引用,支持对象的Weak, UnSafe,而且仅在Android和Ios平台上支持. 现在Delphi XE10.1 Berlin终于增加 ...