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的配置项

1
2
3
4
5
6
7
8
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
在这里我找到了最终获取数据的地方

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

 

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

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
@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行找到了

1
2
Map<String, String> next = (Map<String, String>) 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将配置加载到程序中

1
2
3
4
5
6
for (PropertySource source : result.getPropertySources()) {
	@SuppressWarnings("unchecked")
	Map<String, Object> map = (Map<String, Object>) source
							.getSource();
	composite.addPropertySource(new MapPropertySource(source.getName(), map));
}

 

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值