概述

使用Spring Cloud开发微服务时,ConfigServer是常用的组件,它的作用是将Spring相关的配置项统一起来,其他微服务可以根据实际需要从ConfigServer fetch配置。

本文内容:
1. 部署ConfigServer(配置文件使用native存放而不是git仓库)
2. 如何覆盖ConfigServer中的配置项

ConfigServer简单实践

搭建ConfigServer

首先创建maven project,pom.xml如下

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>1.4.0.RELEASE</version>
</parent>
<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-dependencies</artifactId>
            <version>Camden.RELEASE</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

<dependencies>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-config-server</artifactId>
    </dependency>
</dependencies>

application.properties配置如下:

server.port=8888

#使用本地的配置文件
spring.profiles.active=native

上述的配置很简单,直接使用native 来存放配置文件。
然后在resources目录下新建application-datasource-dev.yml

zeus:
  name: commons datasource configs for develop
  version: 1.0

#kafka配置
kafka:
  host: localhost
  port: 9092

#mongodb配置
spring:
  data:
    mongodb:
      database: test
      host: localhost
      port: 27017

#仅输出ERROR日志
logging:
  level:
    com.netflix.discovery.shared.resolver.aws.ConfigClusterResolver: ERROR

接着编写启动类ConfigServerApplication.java

@SpringBootApplication
@EnableConfigServer
public class ConfigServerApplication {

    public static void main(String[] args) {
        SpringApplication.run(ConfigServerApplication.class, args);
    }
}

运行项目即可。

使用ConfigServer

在需要用到ConfigServer的项目中,引入

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-config</artifactId>
</dependency>

然后我想要用application-datasource-dev.yml这个配置文件,则进行如下配置:

spring:
  application:
    name: examples-manager
  cloud:
    #配置服务器
    config:
      uri: http://localhost:${config.port:8888}
      name: application-datasource                  #配置名称
      profile: dev                                  #最后定向到文件:application-datasource-dev.[properties|yml|

覆盖配置项

场景

成功应用ConfigServer的配置后,发现不能对其中的值进行覆盖。比如ConfigServer中database设置为test,但是我在本地项目中想要用test2

此时不管通过何种方法设置database=test2(如命令行、application.properties、application.yml、SystemProperties等)都不能覆盖test这个值。

原因分析

出现上述情况,是因为来自ConfigServer的配置项优先级最高。Spring application中配置项的优先级大致如下:

bootstrapProperties                                             #来自configServer的值
commandLineArgs                                                 #命令行参数
servletConfigInitParams                                         
servletContextInitParams                                        
systemProperties                                                
systemEnvironment                       
random      
applicationConfig: [classpath:/application.yml]
springCloudClientHostInfo
applicationConfig: [classpath:/bootstrap.yml]
defaultProperties
Management Server

上面的排序是通过implements ApplicationListener<ApplicationPreparedEvent> 然后打印出来的。

通过上面的顺序,我们可以知道,Spring想要得到一个配置的值,就按照上面的顺序一个个去找,找到就直接返回。由于ConfigServer处于最优先级,本地项目不管怎么设置都不能覆盖。

解决方案

方法很简单,我们只需要调整一下优先级顺序即可。直接上代码:

@Component
@Order(Ordered.HIGHEST_PRECEDENCE)
public class ConfigServicePropertyDeprioritizer
        implements ApplicationListener<ApplicationPreparedEvent> {
    private static final String CONFIG_SOURCE = "bootstrapProperties";

    @Override
    public void onApplicationEvent(ApplicationPreparedEvent event) {
        ConfigurableEnvironment environment = event.getApplicationContext()
                .getEnvironment();
        MutablePropertySources sources = environment.getPropertySources();

        //默认使用applicationConfig级别来进行覆盖
        if(sources.contains(CONFIG_SOURCE)){
            sources.addBefore("defaultProperties", sources.get(CONFIG_SOURCE));
        }
    }
}

直接使用上面的类即可。

Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐