sc-config:监听服务端配置变化

这是我参与更文挑战的第 15 天,活动详情查看: 更文挑战

《配置中心 Spring Cloud Config 详解》系列文章更新,一起在技术的路上精进!本系列文章将会介绍Spring Cloud 中提供了分布式配置中心Spring Cloud Config。应用服务中除了实现系统功能的代码,还需要连接资源和其它应用,经常有很多需要在外部配置的数据去调整应用的行为,如切换不同的数据库,设置功能开关等。随着微服务的不断增加,需要系统具备可伸缩和可扩展性,除此之外就是管理相当多的服务实例的配置数据。在应用的开发阶段由各个服务自治,但是到了生产环境之后会给运维带来很大的麻烦,特别是微服务的规模比较大,配置的更新更为麻烦。为此,系统需要建立一个统一的配置管理中心。

在前面的文章,我们主要介绍了 Spring Cloud Config 客户端如何通过 HTTP URI 和服务发下的方式来指定配置服务器,以及相关的实现细节。本文将会介绍客户端实现中对于服务端配置信息变更监听 ConfigServerInstanceProvider 和 EventListener 的相关实现。

ConfigServerInstanceProvider

从前面文章的ConfigServerInstanceProvider构造方式看出,实例化ConfigServerInstanceProvider需要服务发现的客户端DiscoveryClient。其提供的主要方法getConfigServerInstance,通过传入的serviceId参数,获取对应的服务实例。

public class ConfigServerInstanceProvider {
	public ConfigServerInstanceProvider(DiscoveryClient client) {
		this.client = client;
	}

	@Retryable(interceptor = "configServerRetryInterceptor")
	public ServiceInstance getConfigServerInstance(String serviceId) {
		logger.debug("Locating configserver (" + serviceId + ") via discovery");
		List<ServiceInstance> instances = this.client.getInstances(serviceId);
		if (instances.isEmpty()) {
			throw new IllegalStateException(
					"No instances found of configserver (" + serviceId + ")");
		}
		ServiceInstance instance = instances.get(0);
		return instance;
	}
}
复制代码

上述代码实现逻辑很清晰,主要依赖于前面的 DiscoveryClientConfigServiceBootstrapConfiguration 注入的对象DiscoveryClient,通过client获取对应serviceId的实例。

EventListener

下面我们看一下上面配置的两个事件监听器:环境上下文刷新和心跳事件。

环境上下文刷新事件,ContextRefreshedEvent的父类继承自抽象类ApplicationEvent,当ApplicationContext被初始化或者刷新时会唤起该事件。

public class ContextRefreshedEvent extends ApplicationContextEvent {
	 // 创建了一个新的上下文刷新事件,参数是初始化了的ApplicationContext
	public ContextRefreshedEvent(ApplicationContext source) {
		super(source);
	}
}
复制代码

心跳事件定义在discovery client中,如果支持来自discovery server心跳,DiscoveryClient的实现能够广播。提供给监听器一个基本的服务目录状态变更的指示。

public class HeartbeatEvent extends ApplicationEvent {

	private final Object state;
	public HeartbeatEvent(Object source, Object state) { // 1
		super(source);
		this.state = state;
	}

	//
	public Object getValue() { // 2
		return this.state;
	}
}
复制代码
  1. 创建一个新的事件,参数通常为discovery client和状态值,连个参数都不依赖于具体的内容和格式
  2. 代表服务目录的状态值。唯一的需求当目录更新了,该状态值也需要更新,如同一个版本计数器一样简单。

介绍完这两个事件,我们发现他们的监听器都依赖于refresh()方法,下面我们具体看下其实现的功能。

	private void refresh() {
		try {
			String serviceId = this.config.getDiscovery().getServiceId(); // 1
			ServiceInstance server = this.instanceProvider
					.getConfigServerInstance(serviceId);
			String url = getHomePage(server);
			if (server.getMetadata().containsKey("password")) { // 2
				String user = server.getMetadata().get("user");
				user = user == null ? "user" : user;
				this.config.setUsername(user); // 3
				String password = server.getMetadata().get("password");
				this.config.setPassword(password);
			}
			if (server.getMetadata().containsKey("configPath")) {
				String path = server.getMetadata().get("configPath"); // 4
				if (url.endsWith("/") && path.startsWith("/")) {
					url = url.substring(0, url.length() - 1);
				}
				url = url + path;
			}
			this.config.setUri(url);
		}
	}
复制代码
  1. 获取serviceId的服务实例
  2. 刷新获取到的服务实例的元数据信息
  3. 更新用户名、密码
  4. 更新configPath

refresh()方法其实根据上下文环境和心跳事件,进行刷新服务实例ConfigClientProperties中的云数据信息,包括配置的用户名、密码和configPath。

小结

本文主要介绍了 Spring Cloud Config 客户端实现中对于服务端配置信息变更监听 ConfigServerInstanceProvider 和 EventListener 的相关实现。

在本专题开始时的案例,实现了 config client 启动时,根据配置的规则,应用服务会先从 config Server 拉取其对应的配置信息,然后才会初始化 config client 的上下文环境。除此之外还补充了配置的动态刷新和 webHook 应用于配置刷新。下面的文章将会进入 Spring Cloud Config 的应用进阶。

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享