问题描述
在使用 Apollo Client 1.6.0 结合 Spring Cloud 的 @RefreshScope 和 @Value 注解时,遇到以下问题:
- 项目启动时第一次属性注入成功
- 后续配置变更时,@Value 属性会刷新,但总是刷新为第一次的旧值,而不是最新的配置值
<dependency>
<groupId>com.ctrip.framework.apollo</groupId>
<artifactId>apollo-client</artifactId>
<version>1.6.0</version>
</dependency>
问题本质深度解构
解决方案
apollo客户端升级到2.1.0
<dependency>
<groupId>com.ctrip.framework.apollo</groupId>
<artifactId>apollo-client</artifactId>
<version>2.1.0</version>
</dependency>
自定监听
import com.ctrip.framework.apollo.model.ConfigChange;
import com.ctrip.framework.apollo.model.ConfigChangeEvent;
import com.ctrip.framework.apollo.spring.annotation.ApolloConfigChangeListener;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeansException;
import org.springframework.cloud.context.environment.EnvironmentChangeEvent;
import org.springframework.cloud.context.scope.refresh.RefreshScope;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
@Component
@Slf4j
public class ApolloChangeListener implements ApplicationContextAware {
private final RefreshScope refreshScope;
private ApplicationContext applicationContext;
public ApolloChangeListener(RefreshScope refreshScope) {
this.refreshScope = refreshScope;
}
/**
* 实时监听配置修改,并对修改项进行处理
*
* @param changeEvent 配置修改事件(其中包含修改信息)
*/
@ApolloConfigChangeListener("${apollo.bootstrap.namespaces}")
private void configChangeHandler(ConfigChangeEvent changeEvent) {
log.info("================Apollo auto refresh start===========================");
for (String changedKey : changeEvent.changedKeys()) {
ConfigChange configChange = changeEvent.getChange(changedKey);
String oldValue = configChange.getOldValue();
String newValue = configChange.getNewValue();
log.info("changedKey:{},oldValue:{}, newValue:{}", changedKey, oldValue, newValue);
}
refreshContext(changeEvent);
log.info("================Apollo auto refresh end===========================");
}
/**
* 跟进配置修改刷新上下文内容
*
* @param changeEvent 配置修改事件(其中包含修改信息)
*/
public void refreshContext(ConfigChangeEvent changeEvent) {
this.applicationContext.publishEvent(new EnvironmentChangeEvent(changeEvent.changedKeys()));
refreshScope.refreshAll();
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
}