相关文章推荐
还单身的松球  ·  Failed to retrieve ...·  4 月前    · 
想旅行的钥匙  ·  HttpURLConnection--Tra ...·  1 年前    · 

(一)基础知识学习
参见​Spring Cloud 配置客户端技术基础

(二)客户单端配置
主要涉及以下知识:

  • Bootstrap 配置文件
  • 调整 Bootstrap 配置文件路径
  • 覆盖远程配置文件属性
  • 自定义 Bootstrap 配置
  • 自定义 Bootstrap 配置属性源

1、Bootstrap 配置文件
注意事项一:
加载 Bootstrap 配置文件的监听器为:BootstrapApplicationListener

注意事项二:

String configName = environment.resolvePlaceholders("${spring.cloud.bootstrap.name:bootstrap}");

这段代码的意思是,若未配置​ ​spring.cloud.bootstrap.name​ ​​属性,则读取​ ​bootstrap.properties​ ​​或​ ​bootstrap.yml​ ​​为Bootstrap 配置文件;若配置​ ​spring.cloud.bootstrap.name=test​ ​​,则读取​ ​test.properties​ ​​或​ ​test.yml​ ​为Bootstrap 配置文件。

注意事三:

#application.properties
#通过调整 spring.cloud.bootstrap.enabled = false,尝试关闭 bootstrap 上下文
#实际测试结果,没有效果
spring.cloud.bootstrap.enabled = false

原因解析:BootstrapApplicationListener 加载实际早于 ConfigFileApplicationListener(加载 application.yml 的监听器):

  • ConfigFileApplicationListener 的 Ordered.HIGHEST_PRECEDENCE +10(第十一位加载)
  • BootstrapApplicationListener 的 Ordered.HIGHEST_PRECEDENCE + 5(第六位加载)

要想 ​ ​spring.cloud.bootstrap.enabled = false​ ​​ 生效,解决办法之一,就是在JVM的启动参数里设置​ ​--spring.cloud.bootstrap.enabled = false​ ​(这里的启动优先级比这两个更高)

注意事项四:
JVM启动参数的加载逻辑:

SpringApplication.configurePropertySources()

2、调整 Bootstrap 配置文件路径
通过前面可知,BootstrapApplicationListener 加载实际早于 ConfigFileApplicationListener(加载 application.yml 的监听器),所以想在application.yml中调整 Bootstrap 配置文件路径是无法实现的,仍然需要在JVM的启动参数里设置,设置项为​​ ​--spring.cloud.bootstrap.location = config​ ​。调整 Bootstrap 配置文件路径之后,配置文件的加载顺序是什么,这里用一个Demo展示:

在不同的配置文件中设置 application 的名字:
application.yml
spring.application.name = spring-cloud-application
bootstrap.yml
spring.application.name = spring-cloud-bootstrap
spring-cloud.yml
spring.application.name = spring-cloud
config/spring-cloud.yml
spring.application.name = spring-cloud-config

设置JVM启动参数:
//设置 bootstrap 配置文件名为 spring-cloud
--spring.cloud.bootstrap.name = spring-cloud
//设置 Bootstrap 配置文件路径classpath:/config
--spring.cloud.bootstrap.location = config

加载效果:
applicationConfig: [classpath:/application.yml] : {
spring.application.name = spring-cloud-application
}
......
applicationConfig: [classpath:config/spring-cloud.yml] : {
spring.application.name = spring-cloud-application
}
applicationConfig: [classpath:/spring-cloud.yml] : {
spring.application.name = spring-cloud-application
}

备注:spring.application.name 最终读取的是 application.yml 中配置的项,而读取文件的顺序是:
先读 application.yml:不用说,Spring Boot上下文肯定会读到
再读:config/spring-cloud.yml:也不用说,JVM参数设置的bootstrap 配置文件名和路径
最后读spring-cloud.yml:这里就比较奇怪了,为什么还读 resources 路径下的spring-cloud.yml??

3、覆盖远程配置文件属性
默认情况,Spring Cloud 是容许覆盖的:​​ ​spring.cloud.config.allowOverride=true​ ​ 。可以通过JVM启动参数,调整该属性为false(PS:但是这在本地无法生效,本地依然可以覆盖!!!这个仅适用于远程配置,远程无法再覆盖属性):

--spring.cloud.config.allowOverride=false

4、自定义 Bootstrap 配置
(1)创建​​ ​META-INF/spring.factories​ ​​文件,类似于Spring Boot 自定义 Starter;
(2)自定义Bootstrap 配置Configuration

package org.pc.bootstrap;

import org.springframework.context.ApplicationContextInitializer;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.MapPropertySource;
import org.springframework.core.env.MutablePropertySources;
import org.springframework.core.env.PropertySource;

import java.util.HashMap;
import java.util.Map;

/**
*自定义 Bootstrap 配置 Bean
* @author 咸鱼
* @date 2018/10/30 19:22
*/
@Configuration
public class MyConfiguration implements ApplicationContextInitializer {
@Override
public void initialize(ConfigurableApplicationContext applicationContext) {
//从 ConfigurableApplicationContext 获取 ConfigurableEnvironment 实例
ConfigurableEnvironment environment = applicationContext.getEnvironment();
//获取 PropertySources
MutablePropertySources propertySources = environment.getPropertySources();
//定义一个新的 PropertySource
PropertySource propertySource = createPropertySource();
//将新建的 PropertySource 增加到集合中,并且放置在首位
propertySources.addFirst(propertySource);
}

private PropertySource createPropertySource() {
Map<String, Object> source = new HashMap<>();
source.put("name", "咸鱼");
PropertySource propertySource = new MapPropertySource("my-property-source", source);
return propertySource;
}
}

(2)配置​ ​META-INF/spring.factories​ ​​文件,关联 Key ​ ​org.springframework.cloud.bootstrap.BootstrapConfiguration​

org.springframework.cloud.bootstrap.BootstrapConfiguration=\
org.pc.bootstrap.MyConfiguration

通过以上步骤,就可以将自定义的变量放到Bootstrap 上下文中,可以通过​ ​http://localhost:8081/actuator/env​ ​查看新增的属性:

{
"name": "my-property-source",
"properties": {
"name": {
"value": "咸鱼"
}
}
}

5、自定义 Bootstrap 配置属性源
(1)自定义实现 PropertySourceLocator 接口

package org.pc.bootstrap;

import org.springframework.cloud.bootstrap.config.PropertySourceLocator;
import org.springframework.core.env.*;

import java.util.HashMap;
import java.util.Map;

/**
* 自定义 {@link PropertySourceLocator} 实现
* @author 咸鱼
* @date 2018/10/30 19:42
*/
public class MyPropertySourceLocator implements PropertySourceLocator {
@Override
public PropertySource<?> locate(Environment environment) {
//判断是否是 ConfigurableEnvironment 类型
if (environment instanceof ConfigurableEnvironment){
//若是,强转
ConfigurableEnvironment configurableEnvironment = ConfigurableEnvironment.class.cast(environment);
//获取 PropertySources
MutablePropertySources propertySources = configurableEnvironment.getPropertySources();
//将新建的 PropertySource 增加到集合中,并且放置在首位
propertySources.addFirst(createPropertySource());
}
return null;
}

private PropertySource createPropertySource() {
Map<String, Object> source = new HashMap<>();
source.put("nickName", "咸鱼昵称");
//设置名称 来源
PropertySource propertySource = new MapPropertySource("my-property-source-1", source);
return propertySource;
}
}

(2)配置​ ​META-INF/spring.factories​ ​​文件,关联 Key ​ ​org.springframework.cloud.bootstrap.BootstrapConfiguration​

org.springframework.cloud.bootstrap.BootstrapConfiguration=\
org.pc.bootstrap.MyPropertySourceLocator

通过以上步骤,就可以将自定义的变量放到Bootstrap 上下文中,可以通过​ ​http://localhost:8081/actuator/env​ ​查看新增的属性:

{
"name": "my-property-source-1",
"properties": {
"nickName": {
"value": "咸鱼昵称"
}
}
}

(三)客户端和服务端联合配置
参见​三、Spring cloud之服务器配置和客户端配置