1、不同于 Spring cloud config 的配置更新机制(配置更新之后使用 bus 将配置变动推送给各个服务),Spring Cloud Consul Config是通过HTTP的方式跟Consul交互的,更新是实时的吗?
org.springframework.cloud.consul.config.ConfigWathc中定时方法watchConfigKeyValues(),默认每个1秒执行一次(可通过spring.cloud.consul.config.watch.delay自定义时间),去Consul获取最新的信息,配置发生变化时,Spring通过ApplicationEventPublisher重新刷新配置。Consul Config通过这种方式实现实时生效的效果。
2、客户端如何发现配置变更了?
Consul返回的数据中每一项配置都会有"consulIndex"属性,如果更新,属性就会自增。
Spring Cloud Consul Config 就是通过缓存“consulIndex”判断配置是否发生改变。
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
package org.springframework.cloud.consul.config;
import com.ecwid.consul.v1.ConsulClient;
import com.ecwid.consul.v1.QueryParams;
import com.ecwid.consul.v1.Response;
import com.ecwid.consul.v1.kv.model.GetValue;
import io.micrometer.core.annotation.Timed;
import java.beans.ConstructorProperties;
import java.io.Closeable;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
import javax.annotation.PostConstruct;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.cloud.consul.config.ConsulConfigProperties.Format;
import org.springframework.cloud.endpoint.event.RefreshEvent;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationEventPublisherAware;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.util.ReflectionUtils;
import org.springframework.util.StringUtils;
public class ConfigWatch implements Closeable, ApplicationEventPublisherAware {
private static final Log log = LogFactory.getLog(ConfigWatch.class);
private final ConsulConfigProperties properties;
private final ConsulClient consul;
private LinkedHashMap<String, Long> consulIndexes;
private final AtomicBoolean running;
private ApplicationEventPublisher publisher;
private boolean firstTime;
/** @deprecated */
@Deprecated
public ConfigWatch(ConsulConfigProperties properties, List<String> contexts, ConsulClient consul) {
this(properties, consul, new LinkedHashMap());
}
public ConfigWatch(ConsulConfigProperties properties, ConsulClient consul, LinkedHashMap<String, Long> initialIndexes) {
this.running = new AtomicBoolean(false);
this.firstTime = true;
this.properties = properties;
this.consul = consul;
this.consulIndexes = new LinkedHashMap(initialIndexes);
}
public void setApplicationEventPublisher(ApplicationEventPublisher publisher) {
this.publisher = publisher;
}
@PostConstruct
public void start() {
this.running.compareAndSet(false, true);
}
@Scheduled(
fixedDelayString = "${spring.cloud.consul.config.watch.delay:1000}"
)
@Timed("consul.watch-config-keys")
public void watchConfigKeyValues() {
if (this.running.get()) {
Iterator var1 = this.consulIndexes.keySet().iterator();
while(var1.hasNext()) {
String context = (String)var1.next();
if (this.properties.getFormat() != Format.FILES && !context.endsWith("/")) {
context = context + "/";
}
try {
Long currentIndex = (Long)this.consulIndexes.get(context);
if (currentIndex == null) {
currentIndex = -1L;
}
String aclToken = this.properties.getAclToken();
if (StringUtils.isEmpty(aclToken)) {
aclToken = null;
}
Response<List<GetValue>> response = this.consul.getKVValues(context, aclToken, new QueryParams((long)this.properties.getWatch().getWaitTime(), currentIndex.longValue()));
if (response.getValue() != null && !((List)response.getValue()).isEmpty()) {
Long newIndex = response.getConsulIndex();
if (newIndex != null && !newIndex.equals(currentIndex)) {
if (!this.consulIndexes.containsValue(newIndex) && !currentIndex.equals(-1L)) {
ConfigWatch.RefreshEventData data = new ConfigWatch.RefreshEventData(context, currentIndex, newIndex);
this.publisher.publishEvent(new RefreshEvent(this, data, data.toString()));
}
this.consulIndexes.put(context, newIndex);
}
}
} catch (Exception var8) {
if (this.firstTime && this.properties.isFailFast()) {
log.error("Fail fast is set and there was an error reading configuration from consul.");
ReflectionUtils.rethrowRuntimeException(var8);
} else if (log.isTraceEnabled()) {
log.trace("Error querying consul Key/Values for context '" + context + "'", var8);
} else if (log.isWarnEnabled()) {
log.warn("Error querying consul Key/Values for context '" + context + "'. Message: " + var8.getMessage());
}
}
}
}
this.firstTime = false;
}
public void close() {
this.running.compareAndSet(true, false);
}
static class RefreshEventData {
private final String context;
private final Long prevIndex;
private final Long newIndex;
@ConstructorProperties({"context", "prevIndex", "newIndex"})
public RefreshEventData(String context, Long prevIndex, Long newIndex) {
this.context = context;
this.prevIndex = prevIndex;
this.newIndex = newIndex;
}
public String getContext() {
return this.context;
}
public Long getPrevIndex() {
return this.prevIndex;
}
public Long getNewIndex() {
return this.newIndex;
}
public boolean equals(Object o) {
if (o == this) {
return true;
} else if (!(o instanceof ConfigWatch.RefreshEventData)) {
return false;
} else {
ConfigWatch.RefreshEventData other = (ConfigWatch.RefreshEventData)o;
if (!other.canEqual(this)) {
return false;
} else {
label47: {
Object this$context = this.getContext();
Object other$context = other.getContext();
if (this$context == null) {
if (other$context == null) {
break label47;
}
} else if (this$context.equals(other$context)) {
break label47;
}
return false;
}
Object this$prevIndex = this.getPrevIndex();
Object other$prevIndex = other.getPrevIndex();
if (this$prevIndex == null) {
if (other$prevIndex != null) {
return false;
}
} else if (!this$prevIndex.equals(other$prevIndex)) {
return false;
}
Object this$newIndex = this.getNewIndex();
Object other$newIndex = other.getNewIndex();
if (this$newIndex == null) {
if (other$newIndex != null) {
return false;
}
} else if (!this$newIndex.equals(other$newIndex)) {
return false;
}
return true;
}
}
}
protected boolean canEqual(Object other) {
return other instanceof ConfigWatch.RefreshEventData;
}
public int hashCode() {
int PRIME = true;
int result = 1;
Object $context = this.getContext();
int result = result * 59 + ($context == null ? 43 : $context.hashCode());
Object $prevIndex = this.getPrevIndex();
result = result * 59 + ($prevIndex == null ? 43 : $prevIndex.hashCode());
Object $newIndex = this.getNewIndex();
result = result * 59 + ($newIndex == null ? 43 : $newIndex.hashCode());
return result;
}
public String toString() {
return "ConfigWatch.RefreshEventData(context=" + this.getContext() + ", prevIndex=" + this.getPrevIndex() + ", newIndex=" + this.getNewIndex() + ")";
}
}
}
网友评论