您好,登錄后才能下訂單哦!
這篇文章主要介紹Spring Cloud覆寫遠端配置屬性的示例分析,文中介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們一定要看完!
應用的配置源通常都是遠端的Config Server服務器,默認情況下,本地的配置優先級低于遠端配置倉庫。如果想實現本地應用的系統變量和config文件覆蓋遠端倉庫中的屬性值,可以通過如下設置:
spring: cloud: config: allowOverride: true overrideNone: true overrideSystemProperties: false
overrideNone:當allowOverride為true時,overrideNone設置為true,外部的配置優先級更低,而且不能覆蓋任何存在的屬性源。默認為false
allowOverride:標識overrideSystemProperties屬性是否啟用。默認為true,設置為false意為禁止用戶的設置
overrideSystemProperties:用來標識外部配置是否能夠覆蓋系統屬性,默認為true
客戶端通過如上配置,可以實現本地配置優先級更高,且不能被覆蓋。由于我們基于的Spring Cloud
當前版本是 Edgware.RELEASE
,上面的設置并不能起作用,而是使用了 PropertySourceBootstrapProperties
中的默認值。具體情況見issue: https://github.com/spring-cloud/spring-cloud-commons/pull/250 ,我們在下面分析時會講到具體的bug源。
源碼分析
ConfigServicePropertySourceLocator
覆寫遠端的配置屬性歸根結底與客戶端的啟動時獲取配置有關,在獲取到配置之后如何處理?我們看一下spring cloud config中的資源獲取類 ConfigServicePropertySourceLocator 的類圖。
ConfigServicePropertySourceLocator 實質是一個屬性資源定位器,其主要方法是 locate(Environment environment) 。首先用當前運行應用的環境的application、profile和label替換configClientProperties中的占位符并初始化RestTemplate,然后遍歷labels數組直到獲取到有效的配置信息,最后還會根據是否快速失敗進行重試。主要流程如下:
locate(Environment environment) 調用 getRemoteEnvironment(restTemplate, properties, label, state) 方法通過http的方式獲取遠程服務器上的配置數據。實現也很簡單,顯示替換請求路徑path中占位符,然后進行頭部headers組裝,組裝好了就可以發送請求,最后返回結果。
在上面的實現中,我們看到獲取到的配置信息存放在 CompositePropertySource ,那是如何使用它的呢?這邊補充另一個重要的類是PropertySourceBootstrapConfiguration,它實現了ApplicationContextInitializer接口,該接口會在應用上下文刷新之前 refresh() 被回調,從而執行初始化操作,應用啟動后的調用棧如下:
SpringApplicationBuilder.run() -> SpringApplication.run() -> SpringApplication.createAndRefreshContext() -> SpringApplication.applyInitializers() -> PropertySourceBootstrapConfiguration.initialize() PropertySourceBootstrapConfiguration
而上述 ConfigServicePropertySourceLocator 的locate方法會在initialize中被調用,從而保證上下文在刷新之前能夠拿到必要的配置信息。具體看一下initialize方法:
public class PropertySourceBootstrapConfigurationimplements ApplicationContextInitializer<ConfigurableApplicationContext>, Ordered { private int order = Ordered.HIGHEST_PRECEDENCE + 10; @Autowired(required = false) private List<PropertySourceLocator> propertySourceLocators = new ArrayList<>(); @Override public void initialize(ConfigurableApplicationContext applicationContext){ CompositePropertySource composite = new CompositePropertySource( BOOTSTRAP_PROPERTY_SOURCE_NAME); //對propertySourceLocators數組進行排序,根據默認的AnnotationAwareOrderComparator AnnotationAwareOrderComparator.sort(this.propertySourceLocators); boolean empty = true; //獲取運行的環境上下文 ConfigurableEnvironment environment = applicationContext.getEnvironment(); for (PropertySourceLocator locator : this.propertySourceLocators) { //遍歷this.propertySourceLocators PropertySource<?> source = null; source = locator.locate(environment); if (source == null) { continue; } logger.info("Located property source: " + source); //將source添加到PropertySource的鏈表中 composite.addPropertySource(source); empty = false; } //只有source不為空的情況,才會設置到environment中 if (!empty) { //返回Environment的可變形式,可進行的操作如addFirst、addLast MutablePropertySources propertySources = environment.getPropertySources(); String logConfig = environment.resolvePlaceholders("${logging.config:}"); LogFile logFile = LogFile.get(environment); if (propertySources.contains(BOOTSTRAP_PROPERTY_SOURCE_NAME)) { //移除bootstrapProperties propertySources.remove(BOOTSTRAP_PROPERTY_SOURCE_NAME); } //根據config server覆寫的規則,設置propertySources insertPropertySources(propertySources, composite); reinitializeLoggingSystem(environment, logConfig, logFile); setLogLevels(environment); //處理多個active profiles的配置信息 handleIncludedProfiles(environment); } } //... }
下面我們看一下,在 initialize 方法中進行了哪些操作。
根據默認的 AnnotationAwareOrderComparator 排序規則對propertySourceLocators數組進行排序
獲取運行的環境上下文ConfigurableEnvironment
遍歷propertySourceLocators時
調用 locate 方法,傳入獲取的上下文environment
將source添加到PropertySource的鏈表中
設置source是否為空的標識標量empty
source不為空的情況,才會設置到environment中
返回Environment的可變形式,可進行的操作如addFirst、addLast
移除propertySources中的bootstrapProperties
根據config server覆寫的規則,設置propertySources
處理多個active profiles的配置信息
初始化方法 initialize 處理時,先將所有PropertySourceLocator類型的對象的 locate 方法遍歷,然后將各種方式得到的屬性值放到CompositePropertySource中,最后調用 insertPropertySources(propertySources, composite) 方法設置到Environment中。Spring Cloud Context中提供了覆寫遠端屬性的 PropertySourceBootstrapProperties ,利用該配置類進行判斷屬性源的優先級。
private void insertPropertySources(MutablePropertySources propertySources, CompositePropertySource composite) { MutablePropertySources incoming = new MutablePropertySources(); incoming.addFirst(composite); PropertySourceBootstrapProperties remoteProperties = new PropertySourceBootstrapProperties(); new RelaxedDataBinder(remoteProperties, "spring.cloud.config") .bind(new PropertySourcesPropertyValues(incoming)); //如果不允許本地覆寫 if (!remoteProperties.isAllowOverride() || (!remoteProperties.isOverrideNone() && remoteProperties.isOverrideSystemProperties())) { propertySources.addFirst(composite); return; } //overrideNone為true,外部配置優先級最低 if (remoteProperties.isOverrideNone()) { propertySources.addLast(composite); return; } if (propertySources .contains(StandardEnvironment.SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME)) { //根據overrideSystemProperties,設置外部配置的優先級 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); } }
上述實現主要是根據 PropertySourceBootstrapProperties 中的屬性,調整多個配置源的優先級。從其實現可以看到 PropertySourceBootstrapProperties 對象的是被直接初始化,使用的是默認的屬性值而并未注入我們在配置文件中設置的。
修復后的實現:
@Autowired(required = false) private PropertySourceBootstrapProperties remotePropertiesForOverriding; @Override public int getOrder(){ return this.order; private void insertPropertySources(MutablePropertySources propertySources, CompositePropertySource composite) { MutablePropertySources incoming = new MutablePropertySources(); incoming.addFirst(composite); PropertySourceBootstrapProperties remoteProperties = remotePropertiesForOverriding == null ? new PropertySourceBootstrapProperties() : remotePropertiesForOverriding;
以上是“Spring Cloud覆寫遠端配置屬性的示例分析”這篇文章的所有內容,感謝各位的閱讀!希望分享的內容對大家有幫助,更多相關知識,歡迎關注億速云行業資訊頻道!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。