springboot + 携程apllo 配置实时生效(1)-指定生效
springboot + 携程apllo 配置实时生效(2)-全局生效
前两天写了一篇博客,springboot + 携程apollo ,实现修改apollo 配置实时生效,当时写的生效,只是针对某一bean的scope 中的配置从ApolloConfig 中获取更新的值有效,对于其他注解@Value的 Bena Scope 是不能实时生效的,基于Apollo官方文档,要想全局生效,需要使用RefreshScoup.refreshAll(), 把ApolloConfig 中最新的值,更新到有@RefresScope 注释的Bean 中,于是又研究了一番,终于验证成功。
1、RefreshScoup 是需要依赖springcloud的,我们springboot项目中,是没有引入springcloud,所以需要针对刷新功能引入相关依赖。
<!--监控+refresh配置-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
<version>1.4.3.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
<version>1.5.8.RELEASE</version>
</dependency>
有一点需要注意,我们的项目,公司封装的springboot 版本还是在2.0以下,以上引入的依赖spring-cloud-starter-config和spring-boot-starter-actuator 版本如果是2.0以上,启动后会报异常,提示:
ClasspathLoggingApplicationListener pplication failed to start with classpath
搜索了一些资料,说是application.properties中的配置有不对的,但是排查了一圈,也没发现问题所在,最终发现是springBoot 版本和 springcloud版本不兼容导致的。
具体版本兼容可以参看:
spring boot 与spring cloud版本不匹配导致的NoSuchMethodError问题
于是把spring-cloud-starter-config和spring-boot-starter-actuator 版本改为1.x ,最终异常解决。
2、在application.properties中添加配置
management.endpoints.web.exposure.include=*
management.endpoints.enabled-by-default=true
3、启动项,添加@EnableApolloConfig
4、配置apollo的监听
import com.ctrip.framework.apollo.core.ConfigConsts;
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.beans.factory.annotation.Autowired;
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.Service;
@Service
@Slf4j
public class ApolloConfigChanged implements ApplicationContextAware {
ApplicationContext applicationContext;
@Autowired
RefreshScope refreshScope;
//这里指定Apollo的namespace,非常重要,如果不指定,默认只使用application
@ApolloConfigChangeListener(value = {ConfigConsts.NAMESPACE_APPLICATION})
public void onChange(ConfigChangeEvent changeEvent) {
for (String changedKey : changeEvent.changedKeys()) {
log.info("apollo changed namespace:{} Key:{} value:{}", changeEvent.getNamespace(), changedKey, changeEvent.getChange(changedKey));
}
refreshProperties(changeEvent);
}
public void refreshProperties(ConfigChangeEvent changeEvent) {
this.applicationContext.publishEvent(new EnvironmentChangeEvent(changeEvent.changedKeys()));
refreshScope.refreshAll();
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
}
5、apollo 配置读取的Bean 对象和 在其他bean 中注入@Value 使用
import lombok.Data;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.stereotype.Service;
@Data
@RefreshScope
@Service
public class TestJavaConfigBean {
@Value("${cutiyu.test}")
private String test;
}
@RestController
@RequestMapping("/")
@Slf4j
@RefreshScope
public class HelloController {
@Value("${cutiyu.test}")
private String test;
@Autowired
TestJavaConfigBean testJavaConfigBean;
@RequestMapping("/hello")
public String hello() {
String test12 = testJavaConfigBean.getTest();
System.out.println(this.test);
System.out.println(test12);
return "Hello";
}
6、启动项目,更改apollo 配置,并发布后, 可以看到获取的值是能够实时更新的
特别说明:
有些文档,可能是基于springboot + springcloud config 的一些集成,说是全局刷新配置,需要手动刷新,不同的springboot 版本,执行的接口不一样,实测后,结果都是404 ,但是不影响上面的实时生效,特别记录一下。猜测原因,是上面的配置,并不是完整的应用spring cloud 的config 功能,依赖的jar 可能是不完整的,所以相应的刷新接口不存在,而报404错误。
localhost:8080/refresh
localhost:8080/actuator/refresh
localhost:8080/actuator/bus/refresh