zookeeper实现配置中心

来源:互联网 发布:python cnn 代码下载 编辑:程序博客网 时间:2024/06/05 11:05


最近做新系统,搞了个配置中心。本地用ehcache,配置最终存储在zookeeper上。系统启动连接zk,检查指定节点目录是否存在。若不存在,则创建。随后设置监听。节点内容变化则触发监听程序,更新数据到本地缓存。读数据时本地缓存不命中,则读取zk对应路径节点内容到本地。

相关代码示例如下:


1.连接zk逻辑

private static ZooKeeper getInstance(){    if (zooKeeper == null) {        try {            if (INSTANCE_INIT_LOCK.tryLock(2, TimeUnit.SECONDS)) {                try {                    zooKeeper = new ZooKeeper(Environment.ZK_ADDRESS, 20000, null);                    // init cfg root path                    ConfZkClient.createWithParent(Environment.CONF_DATA_PATH);                    zooKeeper.register(new Watcher() {                        @Override                        public void process(WatchedEvent watchedEvent) {                            try {                                logger.info("confcenter: watcher:{}", watchedEvent);                                // session expire, close old and create new                                if (watchedEvent.getState() == Event.KeeperState.Expired) {                                    zooKeeper.close();                                    zooKeeper = null;                                    getInstance();                                }                                String path = watchedEvent.getPath();                                String key = pathToKey(path);                                if (key != null) {                                    // add One-time trigger                                    zooKeeper.exists(path, true);                                    if (watchedEvent.getType() == Event.EventType.NodeDeleted) {                                        ConfClient.remove(key);                                    } else if (watchedEvent.getType() == Event.EventType.NodeDataChanged) {                                        String data = getPathDataByKey(key);                                        ConfClient.update(key, data);                                    }                                }                            } catch (KeeperException e) {                                logger.error("confcenter KeeperException:"+ e.getMessage(), e);                            } catch (InterruptedException e) {                                logger.error("confcenter InterruptedException:" +e.getMessage(), e);                            }                        }                    });                } finally {                    INSTANCE_INIT_LOCK.unlock();                }            }        } catch (InterruptedException e) {           logger.error("confcenter init InterruptedException!" + e.getMessage(), e);        } catch (IOException e) {           logger.error("confcenter init IOException!" + e.getMessage(), e);        }    }    if (zooKeeper == null) {        throw new NullPointerException("confcenter ConfZkClient.zooKeeper is null.");    }    return zooKeeper;}


2.重新初始化置加载逻辑

public class ConfPropertyPlaceholderConfigurer extends PropertyPlaceholderConfigurer {    private static Logger log = LoggerFactory.getLogger(ConfPropertyPlaceholderConfigurer.class);    private String beanName;    private BeanFactory beanFactory;    /**     * @param beanFactoryToProcess     * @param props     * @throws BeansException     */    @Override    protected void processProperties(ConfigurableListableBeanFactory beanFactoryToProcess, Properties props) throws BeansException {        // 初始化StringValueResolver        StringValueResolver valueResolver = new StringValueResolver() {            String placeholderPrefix = "${";            String placeholderSuffix = "}";            @Override            public String resolveStringValue(String strVal) {                StringBuffer buf = new StringBuffer(strVal);                // 如果value值匹配'${***}'                boolean start = strVal.startsWith(placeholderPrefix);                boolean end = strVal.endsWith(placeholderSuffix);                while (start && end) {                    // 替换value值,${***} -> ***,例如${default.key01} -> default.key01                    String key = buf.substring(placeholderPrefix.length(), buf.length() - placeholderSuffix.length());                    // 获取value,从properties、cache、zookeeper                    String zkValue = ConfClient.get(key, "");                    buf = new StringBuffer(zkValue);                    start = buf.toString().startsWith(placeholderPrefix);                    end = buf.toString().endsWith(placeholderSuffix);                }                return buf.toString();            }        };        // init bean define visitor        BeanDefinitionVisitor visitor = new BeanDefinitionVisitor(valueResolver);        // 获取所有的bean定义,替换占位符        String[] beanNames = beanFactoryToProcess.getBeanDefinitionNames();        if (beanNames != null && beanNames.length > 0) {            for (String beanName : beanNames) {                if (!(beanName.equals(this.beanName) && beanFactoryToProcess.equals(this.beanFactory))) {                    BeanDefinition bd = beanFactoryToProcess.getBeanDefinition(beanName);                    visitor.visitBeanDefinition(bd);                }            }        }    }


3.EhCache逻辑

public class ConfClient {    private static Logger logger = LoggerFactory.getLogger(ConfClient.class);    public static Properties localProp = PropertiesUtil.loadProperties("confcenter.properties");    private static Cache cache;    static {        // default use ehcche.xml under src        CacheManager manager = CacheManager.create();        /**         * name:缓存名称         * maxElementsInMemory:缓存最大个数         * overflowToDisk:当内存中对象数量达到maxElementsInMemory时,ehcache将会对象写到磁盘中。         * eternal:对象是否永久有效,一但设置了,timeout将不起作用。         * timeToLiveSeconds:设置对象在失效前允许存活时间(单位:秒)。最大时间介于创建时间和失效时间之间。仅当eternal=false对象不是永久有效时使用,默认是0.,也就是对象存活时间无穷大         * timeToIdleSeconds:设置对象在失效前的允许闲置时间(单位:秒)。仅当eternal=false对象不是永久有效时使用,可选属性,默认值是0,也就是可闲置时间无穷大。         * */        cache = new Cache(Environment.CONF_DATA_PATH, 10000, false, true, 1800, 1800);        manager.addCache(cache);    }    /**     * 初始化配置     *     * @param key     * @param value     */    public static void set(String key, String value) {        if (cache != null) {            logger.info("初始化配置: [{}:{}]", new Object[]{key, value});            cache.put(new Element(key, value));        }    }    /**     * 更新配置     *     * @param key     * @param value     */    public static void update(String key, String value) {        if (cache != null) {            if (cache.get(key)!=null) {                logger.info("更新配置: [{}:{}]", new Object[]{key, value});                cache.put(new Element(key, value));            }        }    }    /**     * 获取配置     *     * @param key     * @param defaultVal     * @return     */    public static String get(String key, String defaultVal) {        if (localProp != null && localProp.containsKey(key)) {            return localProp.getProperty(key);        }        if (cache != null) {            Element element = cache.get(key);            if (element != null) {                return (String) element.getObjectValue();            }        }        String zkData = ConfZkClient.getPathDataByKey(key);        if (zkData != null) {            set(key, zkData);            return zkData;        }        return defaultVal;    }    /**     * 删除配置     *     * @param key     * @return     */    public static boolean remove(String key) {        if (cache != null) {            logger.info("删除配置:key ", key);            return cache.remove(key);        }        return false;    }}

原创粉丝点击