SpringCloud源码--SpringCloudConfig工作流程

首先,我是前端 转 PHP 转 JAVA 的以为小白,文中讲的不对的地方请提出来,也欢迎来喷

起因是我司使用Eureka注册中心和 Configserver配置中心来达到多服务共享配置的问题,我好奇是如何从配置中心获取配置后,将配置写入消费方的。
这便引发了我4个小时追代码的过程


Eureka

废话不多说,首先说说Eureka是个什么东西,其实我也不知道是啥!
首先先上一张看不懂的图片,好吧我承认,这是我看过理解最快的一张图片了

image.png

Eureka 是 Netflix 开发的,一个基于 REST 服务的,服务注册与发现的组件

它主要包括两个组件:Eureka Server 和 Eureka Client

  • Eureka Client:一个Java客户端,用于简化与 Eureka Server 的交互(通常就是微服务中的客户端和服务端)
  • Eureka Server:提供服务注册和发现的能力(通常就是微服务中的注册中心)

各个微服务启动时,会通过 Eureka Client 向 Eureka Server 注册自己,Eureka Server 会存储该服务的信息

也就是说,每个微服务的客户端和服务端,都会注册到 Eureka Server,这就衍生出了微服务相互识别的话题

  • 同步:每个 Eureka Server 同时也是 Eureka Client(逻辑上的)
       多个 Eureka Server 之间通过复制的方式完成服务注册表的同步,形成 Eureka 的高可用
  • 识别:Eureka Client 会缓存 Eureka Server 中的信息
       即使所有 Eureka Server 节点都宕掉,服务消费者仍可使用缓存中的信息找到服务提供者(笔者已亲测)
  • 续约:微服务会周期性(默认30s)地向 Eureka Server 发送心跳以Renew(续约)信息(类似于heartbeat)
  • 续期:Eureka Server 会定期(默认60s)执行一次失效服务检测功能
       它会检查超过一定时间(默认90s)没有Renew的微服务,发现则会注销该微服务节点

Spring Cloud 已经把 Eureka 集成在其子项目 Spring Cloud Netflix 里面

以上都是拷贝的,说白了,Eureka做的就是接口转发的概念


SpringCloudConfig

Spring Cloud Config 的官方介绍文档地址如下:
https://cloud.spring.io/spring-cloud-static/Finchley.RELEASE/single/spring-cloud.html#_spring_cloud_config

英语好的自己读吧,我是懒得看

大致意思是,Spring Cloud Config 提供一种基于客户端与服务端(C/S)模式的分布式的配置管理。我们可以把我们的配置管理在我们的应用之外(config server 端),并且可以在外部对配置进行不同环境的管理,比如开发/测试/生产环境隔离,并且还能够做到实时更新配置。


现在要看是追源码了!!!

首先,配置文件中找到了Eureka的配置项

spring.application.name=quickstart-sample
eureka.client.serviceUrl.defaultZone=${QUICKSTART_EUREKAS:http://${QUICKSTART_USERNAME:admin}:${QUICKSTART_PASSWORD:123123}@localhost:20000/eureka/}
spring.cloud.config.profile=framework,test
spring.cloud.config.label=development-wayne
spring.cloud.config.discovery.enabled=true
spring.cloud.config.discovery.serviceId=configserver
spring.cloud.config.username=${QUICKSTART_USERNAME:admin}
spring.cloud.config.password=${QUICKSTART_PASSWORD:123123}

找到这些,我依旧是一头雾水,好吧,我自闭了~~我想放弃了~
开了15分钟小差,我决定从Maven包下手

在项目中找到spring-cloud-config-client-2.1.0.RELEASE.jar这个JAR包,并随便打开一个文件下载源码(听起来好高大上,我大PHP直接看vendor什么时候还要下载源码,哼~~)

全局搜索serviceId

image.png

看,这里有用到诶!!
那既然有 set 那就一定有 get,我继续找下去,找到getServiceId()的调用方出现了
image.png

无意间看了眼上面,嗯~~ 我猜这应该是心跳吧,他是定时的从配置中心获取配置。

继续走~


在源码的127行我发现了this.config.setUri(uri)字眼,无奈的看了下下面只剩下catch了,算了,就研究这个config吧!
image.png

一样的思维,有set 就一定有 get
image.png

在这里我找到了最终获取数据的地方

response = restTemplate.exchange(uri + path, HttpMethod.GET, entity,
                        Environment.class, args);

接下来就涉及到返回数据的地方了,转眼到spring-cloud-config-server-2.1.0.RELEASE.jar这个包中,我们可以看到SpringCloudConfig定义了一个名为EnvironmentController这样的控制器。

在控制器中我们找到了根据上面uri + path的方式请求的入口,

@RequestMapping("/{name}/{profiles}/{label:.*}")
    public Environment labelled(@PathVariable String name, @PathVariable String profiles,
            @PathVariable String label) {
        if (name != null && name.contains("(_)")) {
            // "(_)" is uncommon in a git repo name, but "/" cannot be matched
            // by Spring MVC
            name = name.replace("(_)", "/");
        }
        if (label != null && label.contains("(_)")) {
            // "(_)" is uncommon in a git branch name, but "/" cannot be matched
            // by Spring MVC
            label = label.replace("(_)", "/");
        }
        Environment environment = this.repository.findOne(name, profiles, label);
        if(!acceptEmpty && (environment == null || environment.getPropertySources().isEmpty())){
             throw new EnvironmentNotFoundException("Profile Not found");
        }
        return environment;
    }

我这里在配置文件中设置了spring.cloud.config.server.jdbc=true所以我这里是走的数据库,还有其他的读取配置方式,可自行查阅
根绝我设置的jdbc方式
上面的findOne使用了JdbcEnvironmentRepository中的实现方式
最后在第95行找到了

Map next = (Map) jdbc.query(this.sql,
                        new Object[] { app, env, label }, this.extractor);

这里的sql可通过配置spring.cloud.config.server.jdbc.sql进行复写
如果没有复写,那么就使用JdbcEnvironmentProperties中默认的SQL语句SELECT KEY, VALUE from PROPERTIES where APPLICATION=? and PROFILE=? and LABEL=?

好了,configserver完成了他的任务(东西好少啊,感觉很容易就找到了)。回过头,我们又要看消费方拿到了返回值做了些什么!!

ConfigServicePropertySourceLocator文件中我们看到,其实configserver做了一个拦截,在启动的时候把配置写了进去

在同文件104行终于找到了最后的方法,通过CompositePropertySource将配置加载到程序中

for (PropertySource source : result.getPropertySources()) {
    @SuppressWarnings("unchecked")
    Map map = (Map) source
                            .getSource();
    composite.addPropertySource(new MapPropertySource(source.getName(), map));
}

其实我想追一下CompositePropertySource的源码,但是我饿~~~~~~了,
第一次写看源码的笔记,可能有些地方我自己懂了就跳过了,如果哪里没写出来,欢迎提出来

你可能感兴趣的:(SpringCloud源码--SpringCloudConfig工作流程)