本文共 4513 字,大约阅读时间需要 15 分钟。
通过上一篇日志,我们已经将一个单机版的apollo server端搭建起来了,并且可以通过官方提供的demo实现最基本的配置文件的读取。接下来我主要通过一个实际的spring项目来演示如何利用apollo的java客户端实现项目的配置文件动态更新。
apollo的Java客户端可以通过纯java API,spring注解,springboot注解等形式绑定到我们的项目中,我项目使用的spring4.x搭建的,因此我使用spring注解方式将apollo客户端添加到我的工程中来。
1.先引入apollo-client的maven依赖
com.ctrip.framework.apollo apollo-client 1.1.0
2.创建自定义namespace,其中application是默认的namespace(一个namespace可以理解成一个properties文件的名称,因为我只用到了properties类型的配置文件)
创建好对应的namespace之后,页面会提示需要发布对应的key-value配置项,如果为空的话会导致Apollo client所在的工程报空指针异常!
3. 工程如何引入在Apollo中的各配置项?
namespace配置文件定位
apollo利用appid、cluster_name、namespace来最终定位一个配置文件, 其中 appid和cluster_name都是作为系统参数在应用启动之前就设置好了,而namespace作为客户端程序初始化的一个参数设定!appid通过在项目的META-INF下面的app.prperties文件中指定,例:app.id=yanghe66966,其中yanghe66966为apollo中创建的一个appid,如何创建官网上面写的很详细,我这里就不罗嗦了
cluster_name通过jvm运行参数指定:“-Dapollo.cluster=default”
default
)加载namespace的获取,在javaconfig中,使用@EnableApolloConfig()注解,加载指定的namespace
@Configuration()@EnableApolloConfig(value = {"application","TEST2.RegistryCenter","TEST2.MessageMiddleware","TEST2.DistributedCaching"}, order = 10)//appllopublic class BasicConfig { { /** * 集群和环境设置未起作用 */ System.setProperty("apollo.meta", "http://192.168.219.130:8080"); System.setProperty("idc", "DEV");//环境 } @Bean public PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() { return new PropertySourcesPlaceholderConfigurer(); }}
创建与四个namespace一一对应的四个本地POJO对象,目的是将指定的配置文件封装到指定对象,便于整个工程调用
如RegistryCenterProperties类的代码如下,@component注解表示当前类的生命周期由spring负责,@value()注解就是使用的spring自带的注解
/** * 注册中心配置项 * @Description: * @author yangcheng * @date: 2019年6月23日 */@Componentpublic class RegistryCenterProperties { Logger logger = LoggerFactory.getLogger(RegistryCenterProperties.class); private final String curNamespace = "TEST2.RegistryCenter"; /** * 是否开启集群模式 */ @Value("${CLUSTER_OPEN}")//官方建议给出默认值,如@Value("${CLUSTER_OPEN:ON}")--默认值为ON private String clusteropen; /** * 当前注册中心name */ @Value("${REGISTER_CENTER_NAME}") private String curRegisterCenterName; /** * zookkeeper相关的配置 */ @Value("${ZK_ADDR}") private String zkAddr; @Value("${ZK_SESSION_OUTTIME}") private int zkSessionOutTime; //初次重试时间 @Value("${ZK_BASE_SLEEP_TIME_MS}") private int zkBaseSleepTimeMs; //最大重试次数 @Value("${ZK_MAX_RETRIES}") private int zkMaxRetries; /** * 监听namespace为TEST2.RegistryCenter的变化 * @param changeEvent */ @ApolloConfigChangeListener(curNamespace) private void anotherOnChange(ConfigChangeEvent changeEvent) { if(curNamespace.equals(changeEvent.getNamespace())){ SetpropertySet = changeEvent.changedKeys(); for (String property : propertySet) { String newval = changeEvent.getChange(property).getNewValue();// System.out.println("old = " + clusteropen +";new = "+newval); /** * 亲测 变化后 properties对象通过Value注解赋值的属性会自动变动到最新值,不过捕获事件到属性值 * 变化有100毫秒左右的延迟! * 可以在app.properties中增加“apollo.autoUpdateInjectedSpringProperties=false”配置 * 关闭Value注解关联的属性自动刷新 */ try { Thread.sleep(500); } catch (InterruptedException e) { logger.error(e.getMessage()); }finally { try { //do something } catch (InterruptedException e) { logger.error("注册中心相关配置参数设定失败"+e.getMessage()); } } } } } public String getClusteropen() { return clusteropen; } public String getCurRegisterCenterName() { return curRegisterCenterName; } public String getZkAddr() { return zkAddr; } public int getZkSessionOutTime() { return zkSessionOutTime; } public int getZkBaseSleepTimeMs() { return zkBaseSleepTimeMs; } public int getZkMaxRetries() { return zkMaxRetries; } @Override public String toString() { return "RegistryCenterProperties [clusteropen=" + clusteropen + ", curRegisterCenterName=" + curRegisterCenterName + ", zkAddr=" + zkAddr + ", zkSessionOutTime=" + zkSessionOutTime + ", zkBaseSleepTimeMs=" + zkBaseSleepTimeMs + ", zkMaxRetries=" + zkMaxRetries + "]"; } }
需要使用对应配置时,只需要将RegistryCenterProperties注入到对应类中而后通过RegistryCenterProperties的get方法,比便可获取到相应的配置了
1.apollo的使用方式有好几种,我这里只演示了使用spring方式引入apollo client的例子,不过大家也开出来了,其使用还是比较简单的,而且如果你原来项目中本来就是使用@value()注解形式引入配置文件的话,那么对已有代码的改动是很小的!我已经将我一个项目配置切换到apollo了。
2.要想在实际项目中使用的话,必须要考虑配置文件的动态配置策略,尤其是形如:zookeeper、消息中间件、分布式缓存等,一旦他的配置信息有变动,如何在不重启应用的情况下,快速切换对应的client,这个问题是必须要解决的,这里给大家提供一个思路(因为我就是这样子做的):譬如消息中间件,项目启动的时候需要将通过javaAPI实例化的client保存起来,然后等到监控到其对应的配置信息发生变动时,直接关闭原client,关闭之后利用新的配置信息重新实例化一个newclient对象!
转载地址:http://spcii.baihongyu.com/