spring cloud config client 手动refresh 不自动刷新问题

1、背景

Spring cloud config 以git为存储学习过程中,发现针对spring cloud config client 增加了@RefreshScope 后,执行curl –X POST http://ip:port/refresh成功后,对应client中的值没有改变。

  • 项目配置

  • Config Server
    • POM 配置
<?xml version="1.0" encoding="UTF-8"?>

  

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">

    <parent>

        <groupId>org.springframework.boot</groupId>

        <artifactId>spring-boot-starter-parent</artifactId>

        <version>1.4.3.RELEASE</version>

    </parent>

    <modelVersion>4.0.0</modelVersion>

  

    <artifactId>config-server</artifactId>

    <packaging>war</packaging>

  

    <name>config-server</name>

    <!-- FIXME change it to the project's website -->

    <url>http://www.example.com</url>

  

    <properties>

        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>

        <maven.compiler.source>1.7</maven.compiler.source>

        <maven.compiler.target>1.7</maven.compiler.target>

    </properties>

    <dependencies>

        <dependency>

            <groupId>junit</groupId>

            <artifactId>junit</artifactId>

            <version>4.11</version>

            <scope>test</scope>

        </dependency>

        <dependency>

            <groupId>org.springframework.cloud</groupId>

            <artifactId>spring-cloud-config-server</artifactId>

        </dependency>

    </dependencies>

  

  

    <!-- 引入spring cloud的依赖 -->

    <dependencyManagement>

        <dependencies>

            <dependency>

                <groupId>org.springframework.cloud</groupId>

                <artifactId>spring-cloud-dependencies</artifactId>

                <version>Camden.SR4</version>

                <type>pom</type>

                <scope>import</scope>

            </dependency>

        </dependencies>

    </dependencyManagement>

    <!-- 添加spring-boot的maven插件 -->

    <build>

        <plugins>

            <plugin>

                <groupId>org.springframework.boot</groupId>

                <artifactId>spring-boot-maven-plugin</artifactId>

            </plugin>

        </plugins>

        <!--解决yaml Do not use @ for indentation错误解决方法-->

        <!--build节点增加内容-->

        <resources>

            <resource>

                <directory>src/main/resources</directory>

                <!--开启过滤,用指定的参数替换directory下的文件中的参数-->

                <filtering>true</filtering>

            </resource>

        </resources>

    </build>

</project>

 

  • Application.yaml
server:

  port: 8003

spring:

  application:

    name: config-server

  cloud:

    config:

      server:

        git:

          uri: https://github.com/liuzdchn/config

          username: [email protected]

          password: lzd13973596

           #默认为首次请求才会clone git 仓库  配置为启动时clone,可提前快速识别错误配置源

          #clone-on-start: true

        health:

          repositories:

            a-foo:

              lable: dev
  • ConfigServer

 

package com;



import org.springframework.boot.SpringApplication;

import org.springframework.boot.autoconfigure.SpringBootApplication;

import org.springframework.cloud.config.server.EnableConfigServer;

import org.springframework.cloud.context.config.annotation.RefreshScope;



@SpringBootApplication

@EnableConfigServer

public class ConfigServer {

    public static void main(String[] args) {

        SpringApplication.run(ConfigServer.class,args);

    }

}

 

  • Config Client  附解决方案
<dependency>

    <groupId>org.springframework.boot</groupId>

    <artifactId>spring-boot-starter-web</artifactId>

</dependency>

<dependency>

    <groupId>org.springframework.cloud</groupId>

    <artifactId>spring-cloud-starter-config</artifactId>

</dependency>

<dependency>

    <groupId>org.springframework.boot</groupId>

    <artifactId>spring-boot-starter-actuator</artifactId>

</dependency>

 

 

server:

  port: 8005

 

spring:

  application:

    #对应config server 所获取配置文件的{application}

    name: provider

  cloud:

    config:

      uri: http://localhost:8003/

      #对应{profile}

      profile: foo

      #对应{lable}

      label: dev

 

package com.controller;



import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.beans.factory.annotation.Value;

import org.springframework.cache.annotation.CacheConfig;

import org.springframework.cache.annotation.Cacheable;

import org.springframework.context.EnvironmentAware;

import org.springframework.core.env.Environment;

import org.springframework.stereotype.Controller;

import org.springframework.web.bind.annotation.GetMapping;

import org.springframework.web.bind.annotation.ResponseBody;



@Controller

public class ConfigClientController implements EnvironmentAware{



    @Value("${profile}") //获取git仓库配置文件中 profile的值

    private String profile;



    @Autowired

    private Environment environment;

    @GetMapping("/profile")

    public @ResponseBody String hello(){
      // 解决refresh请求后,profile变量不更新问题

        return environment.getProperty("profile"); 

    }



    @Override

    public void setEnvironment(Environment environment) {

        this.environment=environment;

    }

}

 

2、问题

 

Refresh 后 configServer端请求配置文件已经更新

 

Client工程中profile 值仍为原始 defalut-2.0-change-0.9
 

3、问题排查

根据上述日志进入org.springframework.cloud.config.client.ConfigServicePropertySourceLocator#locate 整体逻辑
public PropertySource<?> locate(Environment environment) {

    ConfigClientProperties properties = this.defaultProperties.override(environment);

    CompositePropertySource composite = new CompositePropertySource("configService");

    RestTemplate restTemplate = this.restTemplate == null ? this.getSecureRestTemplate(properties) : this.restTemplate;

    Exception error = null;

    String errorBody = null;

    logger.info("Fetching config from server at: " + properties.getRawUri());



    try {

        String[] labels = new String[]{""};

        if (StringUtils.hasText(properties.getLabel())) {

            labels = StringUtils.commaDelimitedListToStringArray(properties.getLabel());

        }



        String state = ConfigClientStateHolder.getState();

        String[] var9 = labels;

        int var10 = labels.length;



        for(int var11 = 0; var11 < var10; ++var11) {

            String label = var9[var11];

            org.springframework.cloud.config.environment.Environment result = this.getRemoteEnvironment(restTemplate, properties, label.trim(), state);

            if (result != null) {

                logger.info(String.format("Located environment: name=%s, profiles=%s, label=%s, version=%s, state=%s", result.getName(), result.getProfiles() == null ? "" : Arrays.asList(result.getProfiles()), result.getLabel(), result.getVersion(), result.getState()));

                if (result.getPropertySources() != null) {

                    Iterator var14 = result.getPropertySources().iterator();



                    while(var14.hasNext()) {

                        org.springframework.cloud.config.environment.PropertySource source = (org.springframework.cloud.config.environment.PropertySource)var14.next();

                        Map<String, Object> map = source.getSource();

                        composite.addPropertySource(new MapPropertySource(source.getName(), map));

                    }

                }



                if (StringUtils.hasText(result.getState()) || StringUtils.hasText(result.getVersion())) {

                    HashMap<String, Object> map = new HashMap();

                    this.putValue(map, "config.client.state", result.getState());

                    this.putValue(map, "config.client.version", result.getVersion());

                    composite.addFirstPropertySource(new MapPropertySource("configClient", map));

                }



                return composite;

            }

        }

    } catch (HttpServerErrorException var17) {

        error = var17;

        if (MediaType.APPLICATION_JSON.includes(var17.getResponseHeaders().getContentType())) {

            errorBody = var17.getResponseBodyAsString();

        }

    } catch (Exception var18) {

        error = var18;

    }



    if (properties.isFailFast()) {

        throw new IllegalStateException("Could not locate PropertySource and the fail fast property is set, failing", (Throwable)error);

    } else {

        logger.warn("Could not locate PropertySource: " + (errorBody == null ? (error == null ? "label not found" : ((Exception)error).getMessage()) : errorBody));

        return null;

    }

}
 
根据背景色的执行过程,主要就是访问http://localhost:8003/provider/foo/dev 利用config server刷新属性文件,并通过debug情况观察数据已经更新到environment变量中,说明数据已经刷新到client中。

org.springframework.cloud.bootstrap.config.PropertySourceBootstrapConfiguration#initialize 这里就是做environment内容bootstrapProperties关联内容更新

public void initialize(ConfigurableApplicationContext applicationContext) {

    CompositePropertySource composite = new CompositePropertySource("bootstrapProperties");

    AnnotationAwareOrderComparator.sort(this.propertySourceLocators);

    boolean empty = true;

    ConfigurableEnvironment environment = applicationContext.getEnvironment();

    Iterator var5 = this.propertySourceLocators.iterator();



    while(var5.hasNext()) {

        PropertySourceLocator locator = (PropertySourceLocator)var5.next();

        PropertySource<?> source = null;

        source = locator.locate(environment);

        if (source != null) {

            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("bootstrapProperties")) {

            propertySources.remove("bootstrapProperties");

        }



        this.insertPropertySources(propertySources, composite);

        this.reinitializeLoggingSystem(environment, logConfig, logFile);

        this.setLogLevels(environment);

    }



}

 

当我们再次访问http://localhost:8005/profile 查看client的profile属性时,发现其仍然是旧属性,这里我理解为当前controller对象的值在client程序启动第一次访问从config server获取到environment环境变量后,已经对变量赋值,后续refresh仅针对environment环境变量更新,并没有更新对象中的profile变量只,故一直显示“没有刷新”。

4、问题解决

当我们排查到变量在refresh后会更新environment变量后,我们可以通过environment.getProperty("profile");解决

@Controller
public class ConfigClientController implements EnvironmentAware{

    @Value("${profile}") //获取git仓库配置文件中 profile的值
    private String profile;

    @Autowired
    private Environment environment;
    @GetMapping("/profile")
    public @ResponseBody String hello(){
        // 解决refresh请求后,profile变量不更新问题
        return environment.getProperty("profile");
    }

    @Override
    public void setEnvironment(Environment environment) {
        this.environment=environment;
    }
}

 

发布了8 篇原创文章 · 获赞 0 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/lzd649648959/article/details/105235914