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)

 





免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM