请相信我,你必定会更优秀!html
背景:系统基于分布式构建,比方如今两台服务,A,B,系统中不少配置文件是共享的。若是修改配置文件,则须要将A,B两个服务上的配置文件进行修改。若是业务扩展,未来有100个服务,1000个服务呢,配置文件的更新无疑成了一件麻烦事。因此咱们必需要有一个配置中心,好比 db,redis等,全部服务都去配置中心获取配置信息,因为配置信息改动不是很频繁,咱们第一次从 db获取到配置信息后,会将它们进行保留(比方放在map中),不至于每次都去 db拉取。请注意,一个新的问题出现了,若是配置中心的某个配置进行了修改,咱们服务中的配置信息如何作到实时性?重启一下线上服务吗?你可能又会想到,开启一个定时线程,固定时间间隔去更新,时间间隔越小,越能保证咱们服务中配置信息的实时性,1m,1s?每1秒去 db拉取一次吗?java
解决方案:zookeeper做配置中心,数据结构适合咱们存储配置信息,监控机制保证客户端数据实时性。node
官网摘抄(https://zookeeper.apache.org/doc/r3.5.4-beta/zookeeperOver.html):web
Conditional updates and watches ZooKeeper supports the concept of watches. Clients can set a watch on a znode. A watch will be triggered and removed when the znode changes. When a watch is triggered, the client receives a packet saying that the znode has changed. If the connection between the client and one of the Zoo Keeper servers is broken, the client will receive a local notification. These can be used to [tbd].
若是你对 zookeeper不了解,请您先移步官网。zookeeper官网redis
开始演示spring
zookeeper 添加配置信息apache
pom中添加maven依赖:bash
<dependency> <groupId>org.apache.zookeeper</groupId> <artifactId>zookeeper</artifactId> <version>3.4.9</version> </dependency>
一、业务配置信息数据结构
package net.uuimi.blog; import java.util.HashMap; import java.util.Map; /** * function: 配置信息 * * @author zhanghaolin * @date 2018年12月22日下午12:49:43 */ public class Constant { public static Map<String, Object> map = new HashMap<String, Object>(); static { map.put("private_key", ""); // 配置1 map.put("public_Key", ""); // 配置2 } }
二、 监控中心maven
package net.uuimi.blog; import java.util.Iterator; import java.util.Map.Entry; import java.util.concurrent.CountDownLatch; import org.apache.zookeeper.WatchedEvent; import org.apache.zookeeper.Watcher; import org.apache.zookeeper.Watcher.Event.EventType; import org.apache.zookeeper.Watcher.Event.KeeperState; import org.apache.zookeeper.ZooKeeper; import org.apache.zookeeper.data.Stat; import org.springframework.beans.factory.InitializingBean; /** * function: 监控中心 * * @author zhanghaolin * @date 2018年12月22日下午12:52:37 */ public class ConstantMonitor implements Watcher, InitializingBean { private static ZooKeeper zookeeper = null; private static ConstantMonitor constantMonitor = null; private static CountDownLatch countDownLatch = new CountDownLatch(1); private static Stat stat = new Stat(); /** * zookeeper链接&初始化配置信息 */ public void afterPropertiesSet() throws Exception { constantMonitor = new ConstantMonitor(); try { zookeeper = new ZooKeeper("127.0.0.1:2181", 2000, constantMonitor); // 我这里用单点演示 countDownLatch.await(); System.out.println("=====================》》 Zookeeper初始化配置信息:"); Iterator<Entry<String, Object>> iterator = Constant.map.entrySet().iterator(); while (iterator.hasNext()) { Entry<String, Object> item = iterator.next(); String name = item.getKey(); byte[] dataBs = zookeeper.getData("/" + name, true, stat); item.setValue(new String(dataBs, "UTF-8")); System.out.println(name + "=" + new String(dataBs, "UTF-8")); } System.out.println("《《===================== Zookeeper初始化配置信息完毕!"); } catch (Exception e) { e.printStackTrace(); } } /** * 监控&更新 */ public void process(WatchedEvent event) { String path = event.getPath(); KeeperState state = event.getState(); EventType type = event.getType(); if (type == EventType.None && state == KeeperState.SyncConnected) { System.out.println("=====================》》 Zookeeper链接成功!"); countDownLatch.countDown(); } else if (type != EventType.None) { try { byte[] dataBs = zookeeper.getData(path, true, stat); String name = path.substring(1); Constant.map.put(name, new String(dataBs, "UTF-8")); System.out.println(String.format("=====================》》 配置信息【update】:%s=%s", name, new String(dataBs, "UTF-8"))); } catch (Exception e) { e.printStackTrace(); } } } }
三、spring扫描
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <bean class="com.web.EnvConstants.ConstantMonitor" /> </beans>
意在服务启动的时候,装载spring.xml,进行配置文件的初始化。
ok!演示以下
package net.uuimi.blog; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; /** * function: 测试 * @author zhanghaolin * @date 2018年12月22日下午10:18:07 */ public class Test { @SuppressWarnings("resource") public static void main(String[] args) throws InterruptedException { ApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext("/springtest.xml"); Thread.sleep(Integer.MAX_VALUE); } }
控制台输出:
请注意,关键点到了,咱们尝试修改配置信息,看程序可否保证信息实时更新
一、咱们在zookeeper修改配置信息
二、控制台监听,输出
完工。
===
遗留问题:细心的你,能够发现,这样写是不支持新增配置信息的同步的。
解决方案:参考zookeeper的子节点监听事件。具体代码再也不呈现。
努力改变本身和身边人的生活。
特别但愿本文能够对您有所帮助,转载请注明出处。感谢你们留言讨论交流。