简单了解一下SpringCloudConfig的properties的匹配原理(上)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_34446485/article/details/81004369

1、简单了解

这是服务端

因为是需要通过网络访问git中的来访问得到properties/yaml

所有必然是需要有控制器来实现处理的。由于是SpringCloud项目,一般会自动打印系统注册端点,即使没有使用actuator。

所以第一步先从控制台简单看下注册了哪些端点

可以看到注册的端点与微服务实战中列出的一样,甚至还要多点,还支持json,通配符等等

具体maven包

org.springframework.cloud.config.server.environment

org.springframework.cloud.config.server.resource

2、查看源码中的两个Controller

扫描二维码关注公众号,回复: 5896335 查看本文章

可见一个个匹配规则对应一个个Controller映射方法,ResourceController与EnvironmentController在不同子包下,简单猜测一下:

Spring项目设计很规范,对于有.yaml .properties.json获取环境的有后缀的url,有-的匹配列为是环境特殊的,而对ResourceController中的匹配规则是/name/…….且没有通配符,没有后缀,就像是普通的Controller,其中name表示applicationName

其中ResourceController中是通过流,最终会转把Environoment转换为properties的字符串形式,再把String返回,但是也支持直接返回流,此时方法均有synchronized以支持同步。

3、查看ResourceController的retrieve方法

该方法是具体处理转化的

方法如下:

synchronized String retrieve(String name, String profile, String label, String path, boolean resolvePlaceholders) throws IOException {
    if (name != null && name.contains("(_)")) {
        name = name.replace("(_)", "/");
    }
  
    if (label != null && label.contains("(_)")) {
        label = label.replace("(_)", "/");
    }
  
    InputStream is = this.resourceRepository.findOne(name, profile, label, path).getInputStream();
    Throwable var7 = null;
  
    String var20;
    try {
        String text = StreamUtils.copyToString(is, Charset.forName("UTF-8"));
        if (resolvePlaceholders) {
            Environment environment = this.environmentRepository.findOne(name, profile, label);
            text = EnvironmentPropertySource.resolvePlaceholders(EnvironmentPropertySource.prepareEnvironment(environment), text);
        }
  
        var20 = text;
    } catch (Throwable var18) {
        var7 = var18;
        throw var18;
    } finally {
        if (is != null) {
            if (var7 != null) {
                try {
                    is.close();
                } catch (Throwable var17) {
                    var7.addSuppressed(var17);
                }
            } else {
                is.close();
            }
        }
  
    }

 猜测:

该控制器的名字ResourceController,把请求路径作为HTTP中的一个资源存在,上面又提到Resource控制器中的映射都是标准的name/…..,与URI别无二致,此时文件即是一种资源,此时通过得到文件路径->得到流->utf-8 String 返回,     EnvironmentPropertySource.resolvePlaceholders(EnvironmentPropertySource.prepareEnvironment(environment),json) 每个方法的都有类似这一步,猜测这可能是进一步判断解析的JSON和原环境是否一致,即是否是由原环境转化得到该JSON

4、查看EnvironmentController的一个方法

  @RequestMapping({"/{label}/{name}-{profiles}.json"})
    public ResponseEntity<String> labelledJsonProperties(@PathVariable String name, @PathVariable String profiles, @PathVariable String label, @RequestParam(defaultValue = "true") boolean resolvePlaceholders) throws Exception {
        this.validateProfiles(profiles);
        Environment environment = this.labelled(name, profiles, label);
        Map<String, Object> properties = this.convertToMap(environment);
        String json = this.objectMapper.writeValueAsString(properties);
        if (resolvePlaceholders) {
            json = EnvironmentPropertySource.resolvePlaceholders(EnvironmentPropertySource.prepareEnvironment(environment), json);
        }
        return this.getSuccess(json, MediaType.APPLICATION_JSON);
    }​
其中this.convertToMap是返回一个有序的LinkedHashMap
而properties实际上是无序的,继承自hashtable,有疑问这里,不懂。。

在EnvironomentController中的是返回Environment或者ResponseEntity【这里返回通过restful把返回对象写入Response流中,是properties对象的【convertToMap方法中定义了返回的map类型:linkedhashmap】

5、关于使用


一开始属性命名与应用名不同,结果如下:

命名方式:demo-dev.properties     应用名称:springcloudconfig-demo

 

    可见此时只能获取应用名称,分支信息,版本信息,无法获取属性值【后来发现此时无法获取值是因为demo-{}.properties中的demo是请求的应用名而不是服务端的应用名,所以请求的url应该是127.0.0.1/demo/dev/master,被误导是因为在SpringMVC中的applicationName可作为相对URI的顶级前缀】

改为springcloudconfig-demo.properties【ps:应用使用了横杠,可能有歧义,最后去掉横杠后应用名:springcloudconfigserverdemo,但考虑到实际我们的客户端一般不可能是和服务端是同名的,所以我在写客户端配置的时候这里的应用名已经换成了客户端的应用名】

这里需要注意就是应用本身把配置委托给git存储,config来管,所以自认而然,应该使用客户端的应用名来表示并区分多个子模块的每个属性文件、yaml文件

结果如下:

此时一切正常,能获取到from=git-default-1.0这个属性值 

【注意:默认的那个applicationName.properties在prod请求的时候也存在,即无论是用的什么环境(prod,test,dev)】

具体代码处:

6、查看控制台日志

Cannot determine local hostname大意是无法确定本地主机名

即本地测试,由于域名是未知【127.0.0.1全是本地回旋地址,无法找到对应域名,所以每次都会把git中的配置文件下载下来并且保存在本地,即相当于缓存无效了】

PS:本想通过给hosts文件增加本地域名映射,使用自定义域名代替127.0.0.1,但是依然不行,仍然是Cannot determine localhostname 

补充:后来测试发现谷歌浏览器和QQ浏览器都将会缓存一个cookie,且在笔记本上本地测试时又支持读取config后缓存在本地,再次访问不会再读取git仓库了,这才是正常行为。。。一开始测试是在公司电脑上

仅供参考

【工作需要,花时间看了点】

github源代码:https://github.com/jxnu-liguobin/SpringCloud-Learning/tree/master/springcloudconfigserverdemo

猜你喜欢

转载自blog.csdn.net/qq_34446485/article/details/81004369