Spring Cloud 使用 Consul 作为配置中心

SpringBoot 专栏收录该内容
56 篇文章 0 订阅

Spring Cloud 使用 Consul 作为配置中心

加载配置

加载配置是通过 ConsulPropertySourceLocator 来实现的,该类是 PropertySourceLocator接口的实现类

Bean 初始化

		@Bean
		public ConsulPropertySourceLocator consulPropertySourceLocator(ConsulConfigProperties consulConfigProperties) {
			return new ConsulPropertySourceLocator(this.consul, consulConfigProperties);
		}

获取配置

获取配置是通过 PropertySourceLocator#locate 方法实现的,最终将获取到属性添加到环境中

  • ConsulPropertySourceLocator#locate

获取配置时,根据应用名称,路径,环境及配置类型拼接相应的路径,然后调用 Consul 获取 KV 值的接口,获取相应的配置,根据类型解析后放入环境中

	@Override
	@Retryable(interceptor = "consulRetryInterceptor")
	public PropertySource<?> locate(Environment environment) {
		if (environment instanceof ConfigurableEnvironment) {
			ConfigurableEnvironment env = (ConfigurableEnvironment) environment;

			String appName = this.properties.getName();

			if (appName == null) {
				appName = env.getProperty("spring.application.name");
			}

			List<String> profiles = Arrays.asList(env.getActiveProfiles());

			String prefix = this.properties.getPrefix();

			List<String> suffixes = new ArrayList<>();
			// 不是文件类型的时候,后缀为 /,否则就是配置文件的后缀
			if (this.properties.getFormat() != FILES) {
				suffixes.add("/");
			} else {
				suffixes.add(".yml");
				suffixes.add(".yaml");
				suffixes.add(".properties");
			}

			// 路径
			String defaultContext = getContext(prefix, this.properties.getDefaultContext());

			for (String suffix : suffixes) {
				this.contexts.add(defaultContext + suffix);
			}
			// 追加环境及文件类型
			for (String suffix : suffixes) {
				addProfiles(this.contexts, defaultContext, profiles, suffix);
			}

			String baseContext = getContext(prefix, appName);

			// 应用名称前缀
			for (String suffix : suffixes) {
				this.contexts.add(baseContext + suffix);
			}
			for (String suffix : suffixes) {
				addProfiles(this.contexts, baseContext, profiles, suffix);
			}

			Collections.reverse(this.contexts);

			CompositePropertySource composite = new CompositePropertySource("consul");

			for (String propertySourceContext : this.contexts) {
				try {
					ConsulPropertySource propertySource = null;
					if (this.properties.getFormat() == FILES) {
						// 获取值
						Response<GetValue> response = this.consul.getKVValue(propertySourceContext, this.properties.getAclToken());
						// 添加当前索引
						addIndex(propertySourceContext, response.getConsulIndex());
						// 如果值不为空,则更新值并初始化
						if (response.getValue() != null) {
							ConsulFilesPropertySource filesPropertySource = new ConsulFilesPropertySource(propertySourceContext, this.consul, this.properties);
							// 解析配置内容
							filesPropertySource.init(response.getValue());
							propertySource = filesPropertySource;
						}
					} else {
						propertySource = create(propertySourceContext, this.contextIndex);
					}
					if (propertySource != null) {
						composite.addPropertySource(propertySource);
					}
				} catch (Exception e) {
					if (this.properties.isFailFast()) {
						log.error("Fail fast is set and there was an error reading configuration from consul.");
						ReflectionUtils.rethrowRuntimeException(e);
					} else {
						log.warn("Unable to load consul config from " + propertySourceContext, e);
					}
				}
			}

			return composite;
		}
		return null;
	}

监听配置

Consul 监听配置是通过定时任务实现的,

Bean 初始化

Bean 的初始化是在 org.springframework.cloud.consul.config.ConsulConfigAutoConfiguration 中实现的

		@Bean
		@ConditionalOnProperty(name = "spring.cloud.consul.config.watch.enabled", matchIfMissing = true)
		public ConfigWatch configWatch(ConsulConfigProperties properties,
		                               ConsulPropertySourceLocator locator,
		                               ConsulClient consul,
		                               @Qualifier(CONFIG_WATCH_TASK_SCHEDULER_NAME) TaskScheduler taskScheduler) {
			return new ConfigWatch(properties, consul, locator.getContextIndexes(), taskScheduler);
		}

监听实现

ConfigWatch 类实现了 ApplicationEventPublisherAwareSmartLifecycle 接口,

  • 启动

当应用启动后,会调用 SmartLifecycle 的 start 方法,然后初始化配置监听,通过向线程池添加一个定时任务,实现配置的定时拉取,定时任务默认周期是 1s

	@Override
	public void start() {
		if (this.running.compareAndSet(false, true)) {
			this.watchFuture = this.taskScheduler.scheduleWithFixedDelay(
				this::watchConfigKeyValues, this.properties.getWatch().getDelay());
		}
	}
  • 监听

监听时会遍历所有的key,根据 key 从 Consul 获取相应的数据,判断 Index 是否发生变化,如果发生变化,则发送 RefreshEvent 事件,需要手动实现事件监听以响应配置bai

	// Timed 是 Prometheus 的监控
	@Timed("consul.watch-config-keys")
	public void watchConfigKeyValues() {
		if (this.running.get()) {
			// 遍历所有的配置的 key
			for (String context : this.consulIndexes.keySet()) {

				// turn the context into a Consul folder path (unless our config format
				// are FILES)
				if (this.properties.getFormat() != FILES && !context.endsWith("/")) {
					context = context + "/";
				}

				// 根据配置返回的 index 判断是否发生变化
				try {
					Long currentIndex = this.consulIndexes.get(context);
					if (currentIndex == null) {
						currentIndex = -1L;
					}

					log.trace("watching consul for context '" + context + "' with index " + currentIndex);

					// use the consul ACL token if found
					String aclToken = this.properties.getAclToken();
					if (StringUtils.isEmpty(aclToken)) {
						aclToken = null;
					}

					// 获取指定的 key
					Response<List<GetValue>> response = this.consul.getKVValues(context, aclToken, new QueryParams(this.properties.getWatch().getWaitTime(), currentIndex));

					// if response.value == null, response was a 404, otherwise it was a
					// 200
					// reducing churn if there wasn't anything
					if (response.getValue() != null && !response.getValue().isEmpty()) {
						Long newIndex = response.getConsulIndex();

						// 判断 key 的 index 是否相等,如果发生变化,则发出 RefreshEvent 事件
						if (newIndex != null && !newIndex.equals(currentIndex)) {
							// don't publish the same index again, don't publish the first
							// time (-1) so index can be primed
							// 没有发布过这个 index 的事件,且不是第一次发布
							if (!this.consulIndexes.containsValue(newIndex) && !currentIndex.equals(-1L)) {
								log.trace("Context " + context + " has new index " + newIndex);
								// 发送事件
								RefreshEventData data = new RefreshEventData(context, currentIndex, newIndex);
								this.publisher.publishEvent(new RefreshEvent(this, data, data.toString()));
							} else if (log.isTraceEnabled()) {
								log.trace("Event for index already published for context " + context);
							}
							this.consulIndexes.put(context, newIndex);
						} else if (log.isTraceEnabled()) {
							log.trace("Same index for context " + context);
						}
					} else if (log.isTraceEnabled()) {
						log.trace("No value for context " + context);
					}

				} catch (Exception e) {
					// only fail fast on the initial query, otherwise just log the error
					if (this.firstTime && this.properties.isFailFast()) {
						log.error("Fail fast is set and there was an error reading configuration from consul.");
						ReflectionUtils.rethrowRuntimeException(e);
					} else if (log.isTraceEnabled()) {
						log.trace("Error querying consul Key/Values for context '" + context + "'", e);
					} else if (log.isWarnEnabled()) {
						// simplified one line log message in the event of an agent
						// failure
						log.warn("Error querying consul Key/Values for context '" + context + "'. Message: " + e.getMessage());
					}
				}
			}
		}
		this.firstTime = false;
	}
  • 0
    点赞
  • 0
    评论
  • 0
    收藏
  • 一键三连
    一键三连
  • 扫一扫,分享海报

打赏
文章很值,打赏犒劳作者一下
相关推荐
<p> <span style="color:#337fe5;"><strong> </strong></span> </p> <p class="MsoNormal"> <span style="color:#000000;font-size:16px;">本课程总计13大章节,115课时,是一门全面的SpringCloud微服务体系化课程。课程共包括</span><span style="color:#000000;font-size:16px;">十三个大章节,涵盖注册中心、网关、熔断、降级、监控、安全、限流等全部体系。</span><span style="color:#000000;font-size:16px;">包含阿里巴巴Nacos,ConsulSpring Cloud Gateway,OAuth2.0 JWT 等主流技术。</span> </p> <p class="MsoNormal"> <span style="color:#000000;font-size:16px;"> </span> </p> <p>   </p> <p> <span style="color:#337fe5;"><strong>[为什么要学习Spring Cloud微服务]</strong></span> </p> <p> <span style="color:#4d555d;"> </span> </p> <p class="ql-long-24357476" style="font-family:"color:#222226;font-size:14px;background-color:#ffffff;"> <span style="font-family:"background-color:#FFFFFF;"><span style="font-size:12px;">SpringCloud作为主流微服务框架,</span><span style="color:#4d555d;font-family:"background-color:#FFFFFF;font-size:12px;">已成为各互联网公司的首选框架,国内外企业占有率持续攀升,</span><span style="font-size:12px;">是Java工程师的必备技能。</span></span><span style="font-family:"background-color:#FFFFFF;font-size:12px;">就连大名鼎鼎的阿里巴巴</span><span style="font-family:"background-color:#FFFFFF;font-size:12px;">dubbo</span><span style="font-family:"background-color:#FFFFFF;font-size:12px;">也正式更名为</span><span style="font-family:"background-color:#FFFFFF;font-size:12px;">Spring Cloud Alibaba</span><span style="font-family:"background-color:#FFFFFF;font-size:12px;">,成为了</span><span style="font-family:"background-color:#FFFFFF;font-size:12px;">Spring Cloud </span><span style="font-family:"background-color:#FFFFFF;font-size:12px;">微服务中的一个子模块。</span><span style="font-family:"background-color:#FFFFFF;font-size:12px;">Spring Cloud是企业架构转型、个人能力提升、架构师进阶的不二选择。</span><span style="font-family:"background-color:#FFFFFF;"> </span> </p> <p class="ql-long-8780922" style="font-size:11pt;color:#494949;">   </p> <p class="ql-long-8780922" style="font-size:11pt;color:#494949;">   </p> <p class="ql-long-24357476" style="font-family:"color:#222226;font-size:14px;background-color:#ffffff;"> <span style="color:#337fe5;"><strong>【推荐你学习这门课的理由:<span style="color:#e53333;">知识体系完整+丰富学习资料】</span></strong></span> </p> <p class="ql-long-24357476" style="font-family:"color:#222226;font-size:14px;background-color:#ffffff;">   </p> <p class="MsoNormal"> 1、本课程总计13大章节,115课时,是一门全面的SpringCloud微服务体系化课程。 </p> <p class="MsoNormal"> 2、课程0基础入门,逐层递进深入,理论和代码相结合。 </p> <p class="MsoNormal"> 3、十三个大章节,涵盖注册中心、网关、熔断、降级、监控、安全、限流等全部体系。 </p> <p class="MsoNormal"> 4、包含阿里巴巴Nacos,ConsulSpring Cloud Gateway,OAuth2.0 JWT 主流技术。 </p> <p style="background:white;"> 5、课程附带230页高清PDF正版课件、Hoxton版本配套项目源码37个、Edgware版本配套项目26个,所有代码均有详细注释。 </p> <p>   </p> <p class="MsoNormal">   </p> <p> <span style="color:#337fe5;">【主讲讲师】</span> </p> <p> <span style="color:#337fe5;"><span style="color:#000000;">尹洪亮Kevin:</span><br /> <span style="color:#000000;">现任职某互联网公司首席架构师,负责系统架构、项目群管理、产品研发工作。</span><br /> <span style="color:#000000;">10余年软件行业经验,具有数百个线上项目实战经验。</span><br /> <span style="color:#000000;">擅长JAVA技术栈、高并发高可用伸缩式微服务架构、DevOps。</span><br /> <span style="color:#000000;">主导研发的蜂巢微服务架构已经成功支撑数百个微服务稳定运行</span></span> </p> <p> <span style="color:#337fe5;"><span style="color:#000000;"> </span></span> </p> <p>   </p> <p class="ql-long-24357476" style="font-family:"color:#222226;font-size:14px;background-color:#ffffff;"> <span style="color:#337fe5;"><strong>【学完后我将达到什么水平?】</strong></span> </p> <p class="MsoNoSpacing" style="margin-left:18.0pt;text-indent:-18.0pt;"> 1、 对Spring Cloud的各个组件能够熟练配置、开发、部署。 </p> <p class="MsoNoSpacing" style="margin-left:18.0pt;text-indent:-18.0pt;"> 2、 吊打一切关于Spring Cloud微服务的笔试面试题 </p> <p class="MsoNoSpacing" style="margin-left:18.0pt;text-indent:-18.0pt;"> 3、 能够上手搭建十分完整的微服务分布式系统,涵盖服务注册与发现、负载、网关、配置中心、监控、安全、熔断等。 </p> <p class="MsoNoSpacing" style="margin-left:18.0pt;text-indent:-18.0pt;"> 4、 对整个微服务体系架构有十分清晰准确的掌握。 </p> <p>   </p> <p class="ql-long-24357476"> <span style="font-family:""> </span> </p> <p class="MsoListParagraph" style="margin-left:36pt;text-indent:-36pt;" align="left"> <strong><span style="color:#337fe5;">【</span><span style="color:#337fe5;">面向人群</span><span style="color:#337fe5;">】</span></strong> </p> <p class="MsoListParagraph" style="margin-left:18.0pt;text-indent:-18.0pt;"> 1、 <span style="color:#4d555d;">不了解微服务是什么,</span>感觉微服务很难、不敢学,<span style="color:#4d555d;">网上资料松散,</span>没有好的学习资料 </p> <p class="MsoListParagraph" style="margin-left:18.0pt;text-indent:-18.0pt;"> 2、 这么多年还一直在写SSH、SSM项目,没有更新过自己的知识体系。 </p> <p class="MsoListParagraph" style="margin-left:18.0pt;text-indent:-18.0pt;"> 3、 Spring Cloud组件太多,不知道应该重点关注和学习哪些。 </p> <p class="MsoListParagraph" style="margin-left:18.0pt;text-indent:-18.0pt;"> 4、 不会搭建微服务项目、依赖项目太多、完全搞不清楚。 </p> <p class="MsoListParagraph" style="margin-left:18.0pt;text-indent:-18.0pt;">   </p> <p class="MsoListParagraph" style="margin-left:18.0pt;text-indent:-18.0pt;"> <span style="color:#337fe5;"><strong>【课程知识体系图】</strong></span> </p> <p class="MsoListParagraph" style="margin-left:18.0pt;text-indent:-18.0pt;"> <span style="color:#337fe5;"><strong><img src="https://img-bss.csdnimg.cn/202007100719132383.png" alt="" /><br /> </strong></span> </p>
©️2020 CSDN 皮肤主题: 编程工作室 设计师:CSDN官方博客 返回首页

打赏

呜呜呜啦啦啦

你的鼓励将是我创作的最大动力

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值