文档章节

聊聊Spring Cloud Config的ConfigClientWatch

go4it
 go4it
发布于 2017/07/22 23:10
字数 786
阅读 32
收藏 1
点赞 0
评论 0

Spring Cloud Config提供了一个ConfigClientWatch功能,可以定时轮询客户端配置的状态,如果状态发生变化,则refresh。

配置文件

spring:
  cloud:
    config:
      uri: http://localhost:8888
      watch:
        enabled: true
        initialDelay: 5000 ##default 180000 ms
        delay: 10000 ##default 500 ms

配置类

spring-cloud-config-client-1.3.1.RELEASE-sources.jar!/org/springframework/cloud/config/client/ConfigClientAutoConfiguration.java

@Configuration
	@ConditionalOnClass(ContextRefresher.class)
	@ConditionalOnBean(ContextRefresher.class)
	@ConditionalOnProperty(value = "spring.cloud.config.watch.enabled")
	protected static class ConfigClientWatchConfiguration {

		@Bean
		public ConfigClientWatch configClientWatch(ContextRefresher contextRefresher) {
			return new ConfigClientWatch(contextRefresher);
		}
	}

ConfigClientWatch

public class ConfigClientWatch implements Closeable, EnvironmentAware {

	private static Log log = LogFactory
			.getLog(ConfigServicePropertySourceLocator.class);

	private final AtomicBoolean running = new AtomicBoolean(false);
	private final ContextRefresher refresher;
	private Environment environment;

	public ConfigClientWatch(ContextRefresher refresher) {
		this.refresher = refresher;
	}

	@Override
	public void setEnvironment(Environment environment) {
		this.environment = environment;
	}

	@PostConstruct
	public void start() {
		this.running.compareAndSet(false, true);
	}

	@Scheduled(initialDelayString = "${spring.cloud.config.watch.initialDelay:180000}", fixedDelayString = "${spring.cloud.config.watch.delay:500}")
	public void watchConfigServer() {
		if (this.running.get()) {
			String newState = this.environment.getProperty("config.client.state");
            String oldState = ConfigClientStateHolder.getState();

			// only refresh if state has changed
			if (stateChanged(oldState, newState)) {
				ConfigClientStateHolder.setState(newState);
				this.refresher.refresh();
			}
		}
	}

	/* for testing */ boolean stateChanged(String oldState, String newState) {
		return (!hasText(oldState) && hasText(newState))
                || (hasText(oldState) && !oldState.equals(newState));
	}

	@Override
	public void close() {
		this.running.compareAndSet(true, false);
	}

}

依赖config.client.state的环境变量,来判断client端配置文件的状态 依赖ContextRefresher去刷新配置/实例

ContextRefresher

spring-cloud-context-1.2.2.RELEASE-sources.jar!/org/springframework/cloud/context/refresh/ContextRefresher.java

public synchronized Set<String> refresh() {
		Map<String, Object> before = extract(
				this.context.getEnvironment().getPropertySources());
		addConfigFilesToEnvironment();
		Set<String> keys = changes(before,
				extract(this.context.getEnvironment().getPropertySources())).keySet();
		this.context.publishEvent(new EnvironmentChangeEvent(keys));
		this.scope.refreshAll();
		return keys;
	}

这个refresh主要做两件事情:

  • 第一件是发布EnvironmentChangeEvent事件
  • 第二件是调用RefreshScope的refreshAll方法

EnvironmentChangeEvent的listener

spring-cloud-context-1.2.2.RELEASE-sources.jar!/org/springframework/cloud/context/properties/ConfigurationPropertiesRebinder.java

@Component
@ManagedResource
public class ConfigurationPropertiesRebinder
		implements ApplicationContextAware, ApplicationListener<EnvironmentChangeEvent> {

	private ConfigurationPropertiesBeans beans;

	private ConfigurationPropertiesBindingPostProcessor binder;

	private ApplicationContext applicationContext;

	private Map<String, Exception> errors = new ConcurrentHashMap<>();

	public ConfigurationPropertiesRebinder(
			ConfigurationPropertiesBindingPostProcessor binder,
			ConfigurationPropertiesBeans beans) {
		this.binder = binder;
		this.beans = beans;
	}

	@Override
	public void setApplicationContext(ApplicationContext applicationContext)
			throws BeansException {
		this.applicationContext = applicationContext;
	}

	/**
	 * A map of bean name to errors when instantiating the bean.
	 *
	 * @return the errors accumulated since the latest destroy
	 */
	public Map<String, Exception> getErrors() {
		return this.errors;
	}

	@ManagedOperation
	public void rebind() {
		this.errors.clear();
		for (String name : this.beans.getBeanNames()) {
			rebind(name);
		}
	}

	@ManagedOperation
	public boolean rebind(String name) {
		if (!this.beans.getBeanNames().contains(name)) {
			return false;
		}
		if (this.applicationContext != null) {
			try {
				Object bean = this.applicationContext.getBean(name);
				if (AopUtils.isCglibProxy(bean)) {
					bean = getTargetObject(bean);
				}
				this.binder.postProcessBeforeInitialization(bean, name);
				this.applicationContext.getAutowireCapableBeanFactory()
						.initializeBean(bean, name);
				return true;
			}
			catch (RuntimeException e) {
				this.errors.put(name, e);
				throw e;
			}
		}
		return false;
	}

	@SuppressWarnings("unchecked")
	private static <T> T getTargetObject(Object candidate) {
		try {
			if (AopUtils.isAopProxy(candidate) && (candidate instanceof Advised)) {
				return (T) ((Advised) candidate).getTargetSource().getTarget();
			}
		}
		catch (Exception ex) {
			throw new IllegalStateException("Failed to unwrap proxied object", ex);
		}
		return (T) candidate;
	}

	@ManagedAttribute
	public Set<String> getBeanNames() {
		return new HashSet<String>(this.beans.getBeanNames());
	}

	@Override
	public void onApplicationEvent(EnvironmentChangeEvent event) {
		rebind();
	}

}

RefreshScope的refreshAll

spring-cloud-context-1.2.2.RELEASE-sources.jar!/org/springframework/cloud/context/scope/refresh/RefreshScope.java

@ManagedOperation(description = "Dispose of the current instance of all beans in this scope and force a refresh on next method execution.")
	public void refreshAll() {
		super.destroy();
		this.context.publishEvent(new RefreshScopeRefreshedEvent());
	}

发布RefreshScopeRefreshedEvent事件

RefreshScopeRefreshedEvent事件listener

spring-cloud-netflix-eureka-client-1.3.1.RELEASE-sources.jar!/org/springframework/cloud/netflix/eureka/EurekaDiscoveryClientConfiguration.java

@Configuration
	@ConditionalOnClass(RefreshScopeRefreshedEvent.class)
	protected static class EurekaClientConfigurationRefresher {

		@Autowired(required = false)
		private EurekaClient eurekaClient;

		@Autowired(required = false)
		private EurekaAutoServiceRegistration autoRegistration;

		@EventListener(RefreshScopeRefreshedEvent.class)
		public void onApplicationEvent(RefreshScopeRefreshedEvent event) {
			//This will force the creation of the EurkaClient bean if not already created
			//to make sure the client will be reregistered after a refresh event
			if(eurekaClient != null) {
				eurekaClient.getApplications();
			}
			if (autoRegistration != null) {
				// register in case meta data changed
				this.autoRegistration.stop();
				this.autoRegistration.start();
			}
		}
	}

spring-cloud-netflix-core-1.2.6.RELEASE-sources.jar!/org/springframework/cloud/netflix/zuul/ZuulConfiguration.java

    @Bean
	public ApplicationListener<ApplicationEvent> zuulRefreshRoutesListener() {
		return new ZuulRefreshListener();
	}
private static class ZuulRefreshListener
			implements ApplicationListener<ApplicationEvent> {

		@Autowired
		private ZuulHandlerMapping zuulHandlerMapping;

		private HeartbeatMonitor heartbeatMonitor = new HeartbeatMonitor();

		@Override
		public void onApplicationEvent(ApplicationEvent event) {
			if (event instanceof ContextRefreshedEvent
					|| event instanceof RefreshScopeRefreshedEvent
					|| event instanceof RoutesRefreshedEvent) {
				this.zuulHandlerMapping.setDirty(true);
			}
			else if (event instanceof HeartbeatEvent) {
				if (this.heartbeatMonitor.update(((HeartbeatEvent) event).getValue())) {
					this.zuulHandlerMapping.setDirty(true);
				}
			}
		}

	}

小结

Spring Cloud Config的代码是有提供ConfigClientWatch,但是实际单纯使用git作为config server的时候,拉取配置的时候得到的state始终是null,因此客户端轮询是起不到刷新效果的。第二个就是这个refresh发布的RefreshScopeRefreshedEvent,eureka会先去更新注册信息为DOWN,然后再UP起来,这个频繁操作有点风险。

© 著作权归作者所有

共有 人打赏支持
go4it
粉丝 50
博文 669
码字总数 465432
作品 0
深圳
聊聊spring cloud gateway的GatewayFilter

序 本文主要研究一下spring cloud gateway的GatewayFilter GatewayFilter spring-cloud-gateway-core-2.0.0.RC2-sources.jar!/org/springframework/cloud/gateway/filter/GatewayFilter.jav......

go4it
06/09
0
0
聊聊spring cloud的RequestHeaderToRequestUri

序 本文主要研究一下spring cloud的RequestHeaderToRequestUriGatewayFilter GatewayAutoConfiguration spring-cloud-gateway-core-2.0.0.RC2-sources.jar!/org/springframework/cloud/gate......

go4it
06/16
0
0
聊聊spring cloud gateway的RedirectToGatewayFilter

序 本文主要研究下spring cloud gateway的RedirectToGatewayFilter GatewayAutoConfiguration spring-cloud-gateway-core-2.0.0.RC2-sources.jar!/org/springframework/cloud/gateway/confi......

go4it
06/13
0
0
聊聊spring cloud gateway的SetStatusGatewayFilter

序 本文主要研究下spring cloud gateway的SetStatusGatewayFilter GatewayAutoConfiguration spring-cloud-gateway-core-2.0.0.RC2-sources.jar!/org/springframework/cloud/gateway/config......

go4it
06/15
0
0
聊聊spring cloud的PreserveHostHeaderGatewayFilter

序 本文主要研究下spring cloud gateway的PreserveHostHeaderGatewayFilter GatewayAutoConfiguration spring-cloud-gateway-core-2.0.0.RC2-sources.jar!/org/springframework/cloud/gatew......

go4it
06/14
0
0
聊聊eureka client的shutdown

序 本文主要研究一下eureka client的shutdown EurekaRegistration spring-cloud-netflix-eureka-client-2.0.0.RC1-sources.jar!/org/springframework/cloud/netflix/eureka/EurekaClientAuto......

go4it
05/04
0
0
聊聊spring cloud gateway的RouteLocator

序 本文主要研究一下spring cloud gateway的RouteLocator RouteLocator spring-cloud-gateway-core-2.0.0.RC2-sources.jar!/org/springframework/cloud/gateway/route/RouteLocator.java 其有......

go4it
06/06
0
0
聊聊spring cloud的RequestRateLimiterGatewayFilter

序 本文主要研究一下spring cloud的RequestRateLimiterGatewayFilter GatewayAutoConfiguration 注意是要有RateLimiter及KeyResolver的bean才生效,默认KeyResolver为PrincipalNameKeyResol......

go4it
06/18
0
0
从架构演进的角度聊聊 Spring Cloud 都做了些什么?

引用 作者:纯洁的微笑 Spring Cloud作为一套微服务治理的框架,几乎考虑到了微服务治理的方方面面,之前也写过一些关于Spring Cloud文章,主要偏重各组件的使用,本次分享主要解答这两个问题...

xixingzhe
2017/11/02
0
0
聊聊spring cloud gateway的RemoveHopByHopHeadersFilter

序 本文主要研究一下spring cloud gateway的RemoveHopByHopHeadersFilter GatewayAutoConfiguration spring-cloud-gateway-core-2.0.0.RC1-sources.jar!/org/springframework/cloud/gateway......

go4it
05/30
0
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

JavaEE——JavaScript

声明:本栏目所使用的素材都是凯哥学堂VIP学员所写,学员有权匿名,对文章有最终解释权;凯哥学堂旨在促进VIP学员互相学习的基础上公开笔记。 JavaScript 内置对象 String对象方法: date对象...

凯哥学堂
7分钟前
0
0
Git 远程代码回滚master

方式一(推荐): git revert commit-id 方式二(不推荐):不推荐原因:推送到线上后,其它开发人员需要重新clone git reset --hard commit-id git push origin HEAD --force...

浮躁的码农
7分钟前
0
0
Elasticesearch学习(7)—— ES查询与Java API的对应关系

1、普通查询 类型 ES查询语句 Java查询实现 结果 查询格式 { "query": { "bool": { "must": [], "must_not": [], "should": [], "filter": [] } }, "from": 0, "size": 10, "sort": [] } Que......

叶枫啦啦
8分钟前
4
0
getElementsByClassName()与getElementById()区别

1.document.getElementsByClassName() 返回的是数组 使用:document.getElementsByClassName("className")[0].innerText='具体内容' 2.document.getElementById() 返回的是单个元素 使用:d......

botkenni
19分钟前
0
0
MyBatis入门

一、安装 <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>x.x.x</version></dependency> 二、从 XML 中构建 SqlSessionFactory String r......

一个yuanbeth
19分钟前
0
0
聊聊spring cloud的LoadBalancerAutoConfiguration

序 本文主要研究一下spring cloud的LoadBalancerAutoConfiguration RibbonAutoConfiguration spring-cloud-netflix-ribbon-2.0.0.RC2-sources.jar!/org/springframework/cloud/netflix/ribb......

go4it
22分钟前
0
0
【转】使用Lombok来优雅的编码

前言 Lombok 是一种 Java™ 实用工具,可用来帮助开发人员消除 Java 的冗长,尤其是对于简单的 Java 对象(POJO)。它通过注解实现这一目的。 正文 添加依赖 在 pom.xml 文件中添加相关依赖:...

HAVENT
24分钟前
0
0
Dubbo 源码解读 —— 可支持序列化及自定义扩展

一、概述 从源码中,我们可以看出来。目前,Dubbo 内部提供了 5 种序列化的方式,分别为 fastjson、Hessian2、Kryo、fst 及 Java原生支持的方式 。 针对不同的序列化方式,对比内容如下: 名...

Ryan-瑞恩
32分钟前
0
0
MySQL内存设置—— MySQL server has gone away

set global max_allowed_packet=268435456

一梦心草
41分钟前
0
0
推导式

列表、集合和字典推导式 列表推导式是Python最受喜爱的特性之一。它允许用户方便的从一个集合过滤元素,形成列表,在传递参数的过程中还可以修改元素。形式如下: [expr for val in collect...

火力全開
46分钟前
0
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部