情景描述
最近在修复Eureka的静态页面加载不出的缺陷时,最终发现是远程GIT仓库将静态资源访问方式配置给禁用了(spring.resources.add-mappings=false)。虽然最后直接修改远程GIT仓库的此配置项给解决了(spring.resources.add-mappings=true),但是从中牵涉出的配置读取优先级我们必须好好的再回顾下
springcloud config读取仓库配置
通过config client模块来读取远程的仓库配置,只需要在boostrap.properties文件中配置如下属性即可
spring.application.name=eureka spring.cloud.config.uri=http://localhost:8888 spring.cloud.config.name=dev spring.cloud.config.username=dev spring.cloud.config.password=dev
其就会以GET方式去请求http://localhost:8888/eureka/dev地址从而将配置拉取下来。
当然上述的API地址也是需要被访问服务器部署了config server服务方可调用,具体的细节就不展开了
外部源读取优先级
我们都知道spring的配置属性管理均是存放在Enviroment对象中,就以普通项目StandardEnvironment为例,其配置的存放顺序可罗列如下
顺位 | key | 来源 | 说明 |
---|---|---|---|
1 | commandLineArgs | 传入main函数的参数列表 | Program arguments |
2 | systemProperties | System.getProperties() | JDK属性列表、操作系统属性、-D开头的VM属性等 |
3 | systemEnvironment | System.getEnv() | 环境属性,例如JAVA_HOME/M2_HOME |
4 | ${file_name} | 配置文件 | 例如application.yml |
5 | defaultProperties | SpringApplicationBuilder#properties() |
那么远程读取的配置的存放应该放在上述的哪个位置呢?
我们都知道boostrap上下文通过暴露org.springframework.cloud.bootstrap.config.PropertySourceLocator接口来方便集成第三方的外部源配置读取,比如本文提及的config client模块中的org.springframework.cloud.config.client.ConfigServicePropertySourceLocator实现类。
但最终将外部源配置读取以及插入至Environment对象中则是通过org.springframework.cloud.bootstrap.config.PropertySourceBootstrapConfiguration类来完成的。
PropertySourceBootstrapConfiguration
此类也是ApplicationContextInitializer接口的实现类,阅读过cloud源码的都知道,此类被调用是在子类上下文初始化的时候,我们主要看下其复写的initialize()方法
@Override public void initialize(ConfigurableApplicationContext applicationContext) { CompositePropertySource composite = new CompositePropertySource( BOOTSTRAP_PROPERTY_SOURCE_NAME); // 对在boostrap上下文类型为PropertySourceLocator的bean集合进行排序 AnnotationAwareOrderComparator.sort(this.propertySourceLocators); boolean empty = true; ConfigurableEnvironment environment = applicationContext.getEnvironment(); for (PropertySourceLocator locator : this.propertySourceLocators) { PropertySource<?> source = null; // 读取外部配置源 source = locator.locate(environment); if (source == null) { continue; } logger.info("Located property source: " + source); composite.addPropertySource(source); empty = false; } if (!empty) { MutablePropertySources propertySources = environment.getPropertySources(); String logConfig = environment.resolvePlaceholders("${logging.config:}"); LogFile logFile = LogFile.get(environment); if (propertySources.contains(BOOTSTRAP_PROPERTY_SOURCE_NAME)) { propertySources.remove(BOOTSTRAP_PROPERTY_SOURCE_NAME); } // 插入至Environment环境对象中 insertPropertySources(propertySources, composite); reinitializeLoggingSystem(environment, logConfig, logFile); setLogLevels(applicationContext, environment); handleIncludedProfiles(environment); } }
直接观察对应的insertPropertySources()方法
private void insertPropertySources(MutablePropertySources propertySources, CompositePropertySource composite) { // 外部源配置集合 MutablePropertySources incoming = new MutablePropertySources(); incoming.addFirst(composite); PropertySourceBootstrapProperties remoteProperties = new PropertySourceBootstrapProperties(); // 从外部源配置源集合中读取PropertySourceBootstrapProperties的相关属性 // 例如spring.cloud.config.overrideSystemProperties等属性 Binder.get(environment(incoming)).bind("spring.cloud.config", Bindable.ofInstance(remoteProperties)); // spring.cloud.config.allow-override=false或者spring.cloud.config.override-none=false且spring.cloud.config.override-system-properties=true if (!remoteProperties.isAllowOverride() || (!remoteProperties.isOverrideNone() && remoteProperties.isOverrideSystemProperties())) { propertySources.addFirst(composite); return; } // spring.cloud.config.override-none=true则处于最低读取位 if (remoteProperties.isOverrideNone()) { propertySources.addLast(composite); return; } // 根据spring.cloud.config.override-system-properties属性判断是放在systemProperties前还是后 if (propertySources .contains(StandardEnvironment.SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME)) { if (!remoteProperties.isOverrideSystemProperties()) { propertySources.addAfter( StandardEnvironment.SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME, composite); } else { propertySources.addBefore( StandardEnvironment.SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME, composite); } } else { propertySources.addLast(composite); } }
对上述的代码描述作下总结
1.上述的配置属性均会映射到PropertySourceBootstrapProperties实体类中,且其中的默认值罗列如下
属性 | 默认值 | 说明 |
---|---|---|
spring.cloud.config.allow-override | true | 外部源配置是否可被覆盖 |
spring.cloud.config.override-none | false | 外部源配置是否不覆盖任何源 |
spring.cloud.config.override-system-properties | true | 外部源配置是否可覆盖本地属性 |
2.针对相应的属性的值对应的外部源在Environment对象中的读取优先级,罗列如下
属性 | 读取优先级 |
---|---|
spring.cloud.config.allow-override=false | 最高 |
spring.cloud.config.override-none=false&&spring.cloud.config.override-system-properties=true | 最高(默认) |
spring.cloud.config.override-none=true | 最低 |
spring上下文无systemEnvironment属性 | 最低 |
spring上下文有systemEnvironment属性 && spring.cloud.config.override-system-properties=false | 在systemEnvironment之后 |
spring上下文有systemEnvironment属性 && spring.cloud.config.override-system-properties=false | 在systemEnvironment之前 |
即默认情况下,外部源的配置属性的读取优先级是最高的。
且除了spring.cloud.config.override-none=true的情况下,其他情况下外部源的读取优先级均比本地配置文件高。
Note:值得注意的是,如果用户想复写上述的属性,则放在bootstrap.yml|application.yml配置文件中是无效的,根据源码分析只能是自定义一个PropertySourceLocator接口实现类并放置在相应的spring.factories文件中方可生效。
自定义PropertySourceLocator接口
针对上文描述,假设有这么一个场景,远程仓库的配置都是公有的,我们也不能修改它,我们只在项目中去复写相应的配置以达到兼容的目的。那么用户就需要自定义去编写接口了
1.编写PropertySourceLocator接口实现类
package com.example.configdemo.propertysource; import org.springframework.cloud.bootstrap.config.PropertySourceLocator; import org.springframework.core.Ordered; import org.springframework.core.annotation.Order; import org.springframework.core.env.Environment; import org.springframework.core.env.MapPropertySource; import org.springframework.core.env.PropertySource; import java.util.HashMap; import java.util.Map; /** * @author nanco * @create 19/9/22 * @description 自定义的PropertySourceLocator的顺序应该要比远程仓库读取方式要优先 * @see org.springframework.cloud.config.client.ConfigServicePropertySourceLocator */ @Order(value = Ordered.HIGHEST_PRECEDENCE + 1) public class CustomPropertySourceLocator implements PropertySourceLocator { private static final String OVERRIDE_ADD_MAPPING = "spring.resources.add-mappings"; @Override public PropertySource<?> locate(Environment environment) { Map<String, Object> customMap = new HashMap<>(2); // 远程仓库此配置为false,本地进行复写 customMap.put(OVERRIDE_ADD_MAPPING, "true"); return new MapPropertySource("custom", customMap); } }
2.编写BootstrapConfiguration
package com.example.configdemo.propertysource; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; /** * @author nanco * @create 19/9/22 */ @Configuration public class CustomBootstrapConfiguration { @Bean("customPropertySourceLocator") public CustomPropertySourceLocator propertySourceLocator() { return new CustomPropertySourceLocator(); } }
3.在src\main\resources目录下创建META-INF\spring.factories文件
# Bootstrap components org.springframework.cloud.bootstrap.BootstrapConfiguration=\ com.example.configdemo.propertysource.CustomBootstrapConfiguration
4.运行main函数即可
小结
默认情况下,外部源配置拥有最高的优先级。在spring.cloud.config.override-none=false的情况下,外部源配置也比本地文件拥有更高的优先级。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持小牛知识库。
我在这里有一些关于ActiveMQ配置和优先级的类似领域的问题。我目前正在配置ActiveMQ代理以关闭消息持久性。 根据文档,我知道它可以通过代理配置来实现: XML配置文件() 客户端的URI(TCP://localhost:61616?persistent=false) 代理端的 URI-XML配置文件(TCP://localhost:61616?persistent=false)。 我的第
我正在做一个新的项目,第一次使用Spring-Boot。 传统上,在使用Spring和属性文件进行配置时,我在发行版(WAR)中提供了默认属性,并允许在某个文档位置重写它们。 例如: 这将允许我们在不丢失本地系统配置的情况下重新部署应用程序。 我喜欢Spring,因为它允许我们遵守惯例,这让我担心我可能做错了属性级联。 什么是提供包含在发行版中的外部化属性的最合适的方法,该属性具有合理的默认值(嵌
本文向大家介绍java线程优先级原理详解,包括了java线程优先级原理详解的使用技巧和注意事项,需要的朋友参考一下 java 中的线程优先级的范围是1~10,默认的优先级是5。10最高。 MIN_PRIORITY 1 MAX_PRIORITY 10 NORM_PRIORITY 5 优先级高的获得cpu的几率更大些,不是优先级高的就先执行完,线程优先级随机特性 在java中,线程的优先级具有继承性,
问题内容: 我按以下顺序设置了线程的优先级 先是A然后是B,然后是C。但是当我在下面的程序中运行时,有时B在A之前运行。我不理解这种执行方式,因为我将B的优先级设置为小于A的优先级。 } 问题答案: 线程优先级可能不是您认为的那样。 线程的优先级是对操作系统的建议,在涉及这两个线程的任何调度或CPU分配决策点中,一个线程优先于另一个线程。但是,如何实现这一点取决于操作系统和JVM的实现。 Java
本文向大家介绍Java 线程优先级详解及实例,包括了Java 线程优先级详解及实例的使用技巧和注意事项,需要的朋友参考一下 Java 线程优先级详解及实例 操作系统基本采用时分的调度运行线程,操作系统会分出一个个时间片,线程会被分配到若干个时间片,当线程的时间片用完了就会发生线程调度,并且等待着下次调度,线程被分配到的时间片多少也就决定了线程使用处理器资源的多少,而线程优先级就是决定线程能够分配多
本文向大家介绍Java 多线程优先级实例详解,包括了Java 多线程优先级实例详解的使用技巧和注意事项,需要的朋友参考一下 Java 多线程优先级实例详解 线程的优先级将该线程的重要性传递给调度器。尽管CPU处理现有线程集的顺序是不确定的,但是调度器将倾向于让优先权最高的线程先执行。 你可以用getPriority()来读取现有线程的优先级,并且在任何时刻都可以通过setPriority()来修改