springboot Properties加载顺序源码分析

关于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)

 




猜你喜欢

转载自www.cnblogs.com/exmyth/p/11349575.html