Tutorial 2 注解式分布式的配置文件高级篇: 配置更新的通知(最佳实践) ======= 在 [Tutorial 1](Tutorial1.html) 里, 我们实现了一个简单的Redis服务程序,它使用分布式配置进行管理,此Redis的配置文件存储在分布式服务器 disconf-web 上。 也许有一天,我们需要更新Redis的Host和Port配置数据。由于 redis是根据配置生成的实例,因此,这种情况下,你有三种选择: - 不使用Disconf([Tutorial 1](Tutorial1.html) 里第一部分的使用方法)。那么你需要 更改线上机器的配置文件 redis.properties,重启服务就可以了。 - 使用Disconf, 采用 [Tutorial 1](Tutorial1.html) 里第二部分的使用的方案。那么你需要 更改 分布式服务器 disconf-web 上的 redis.properties 文件。 然后重启服务就可以了。和第一种方法的区别在于,不需要更改线上机器的配置文件。 - 使用Disconf,采用 [Tutorial 1](Tutorial1.html) 里第二部分的使用的方案,并额外加上本Tutorial的方案,那么你 只需要 更改 分布式服务器 disconf-web 上的 redis .properties 文件。然后服务的配置自动生效。此过程无需要重新启动服务。 本教程就是阐述如何通过简单的配置和极简代码实现第三步的功能。 ## 第一步:准备工作 完成 [Tutorial 1](Tutorial1.html) 上第二部分方案里的步骤。 ## 第二步:修改 SimpleRedisService,支持Redis重连接 在这里,我们这个类添加了一个方法,重新生成了一个Jedis对象,代码如下: /** * 更改Jedis */ public void changeJedis() { LOGGER.info("start to change jedis hosts to: " + jedisConfig.getHost() + " : " + jedisConfig.getPort()); jedis = JedisUtil.createJedis(jedisConfig.getHost(), jedisConfig.getPort()); LOGGER.info("change ok."); } 之所以添加这个函数的原因是:在配置更新时,此函数要被调用,从而更改Jedis实例。 整个类的完整代码如下: package com.example.disconf.demo.service; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.DisposableBean; import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Scope; import org.springframework.stereotype.Service; import com.example.disconf.demo.config.JedisConfig; import com.example.disconf.demo.utils.JedisUtil; import redis.clients.jedis.Jedis; /** * 一个简单的Redis服务 * * @author liaoqiqi * @version 2014-6-17 */ @Service @Scope("singleton") public class SimpleRedisService implements InitializingBean, DisposableBean { protected static final Logger LOGGER = LoggerFactory.getLogger(SimpleRedisService.class); // jedis 实例 private Jedis jedis = null; /** * 分布式配置 */ @Autowired private JedisConfig jedisConfig; /** * 关闭 */ public void destroy() throws Exception { if (jedis != null) { jedis.disconnect(); } } /** * 进行连接 */ public void afterPropertiesSet() throws Exception { jedis = JedisUtil.createJedis(jedisConfig.getHost(), jedisConfig.getPort()); } /** * 获取一个值 * * @param key * * @return */ public String getKey(String key) { if (jedis != null) { return jedis.get(key); } return null; } /** * 更改Jedis */ public void changeJedis() { LOGGER.info("start to change jedis hosts to: " + jedisConfig.getHost() + " : " + jedisConfig.getPort()); jedis = JedisUtil.createJedis(jedisConfig.getHost(), jedisConfig.getPort()); LOGGER.info("change ok."); } } ## 第三步: 撰写配置更新回调类 当配置更新时,应用程序要得到通知。因此我们要写一个回调类来响应此“通知”。完整的类如下: package com.example.disconf.demo.service.callbacks; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Scope; import org.springframework.stereotype.Service; import com.baidu.disconf.client.common.annotations.DisconfUpdateService; import com.baidu.disconf.client.common.update.IDisconfUpdate; import com.example.disconf.demo.config.Coefficients; import com.example.disconf.demo.config.JedisConfig; import com.example.disconf.demo.service.SimpleRedisService; /** * 更新Redis配置时的回调函数 * * @author liaoqiqi * @version 2014-6-17 */ @Service @Scope("singleton") @DisconfUpdateService(classes = {JedisConfig.class}, itemKeys = {Coefficients.key}) public class SimpleRedisServiceUpdateCallback implements IDisconfUpdate { protected static final Logger LOGGER = LoggerFactory.getLogger(SimpleRedisServiceUpdateCallback.class); @Autowired private SimpleRedisService simpleRedisService; /** * */ public void reload() throws Exception { simpleRedisService.changeJedis(); } } **具体步骤是:** - 撰写此类,实现 IDisconfUpdate 接口。此类必须是JavaBean,Spring托管的,且 "scope" 都必须是singleton的。 - 添加 @DisconfUpdateService 注解,classes 值加上 JedisConfig.class ,表示当 JedisConfig.class 这个配置文件更新时,此回调类将会被调用。或者,使用 confFileKeys 也可以。 - 在函数 reload() 里调用 SimpleRedisService 的 changeJedis() 方法 ### 回调类与配置类放在一起 如果你觉得写两个类太累,在某些场景下,则可以将回调与配置类放在一起的。 /** * Redis配置文件 * * @author liaoqiqi * @version 2014-6-17 */ @Service @Scope("singleton") @DisconfFile(filename = "redis.properties") @DisconfUpdateService(classes = {JedisConfig.class}) public class JedisConfig implements IDisconfUpdate { protected static final Logger LOGGER = LoggerFactory.getLogger(JedisConfig.class); // 代表连接地址 private String host; // 代表连接port private int port; /** * 地址, 分布式文件配置 * * @return */ @DisconfFileItem(name = "redis.host", associateField = "host") public String getHost() { return host; } public void setHost(String host) { this.host = host; } /** * 端口, 分布式文件配置 * * @return */ @DisconfFileItem(name = "redis.port", associateField = "port") public int getPort() { return port; } public void setPort(int port) { this.port = port; } @Override public void reload() throws Exception { LOGGER.info("host: " + host); } } ## 完结 至此,支持配置更新的 分布式配置文件 的撰写就已经写完了。 当用户在 disconf-web 上更新配置时,你的服务里的Redis就会指向新的地址。