配置中心案例

工作中有这样的一个场景:数据库用户名和密码信息放在一个配置文件中,应用读取该配置文件,配置文件信息放入缓存。 若数据库的用户名和密码改变时候,还需要重新加载缓存,比较麻烦。通过zooKeeper可以轻松完成,当数据库发生变化时自动完成缓存同步。

设计思路:

  1. 连接zookeeper服务器。
  2. 读取zookeeper中的配置信息,注册watcher监听器,读取配置信息存入本地变量。
  3. 当zookeeper中的配置信息发生变化时,通过watcher的回调方法捕获数据变化事件。
  4. 回调中重新获取配置信息,并注册新的监听事件。

获取配置信息之前先创建好配置信息节点数据:

create /config "dbconfig"
 create /config/url "jdbc:mysql://localhost:3306/zookeeper"
 create /config/username "root"
 create /config/password "123456"
package com.huazai.zookeeper.zkexample.config;

import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.ZooKeeper;

import java.util.concurrent.CountDownLatch;

/**
 * @author pyh
 * @date 2021/5/19 0:20
 */
public class ZookeeperConnection {
    public static void main(String[] args) {
        connect();
    }

    public static ZooKeeper zooKeeper;

    public static ZooKeeper connect() {
        try {
            // 由于连接zookeeper服务器是异步连接,需要CountDownLatch阻塞主线程,等待子线程连接结果后反馈给主线程
            CountDownLatch countDownLatch = new CountDownLatch(1);
            /*
                connectString:服务器的ip和端口
                sessionTimeout:客户端与服务器之间的会话超时时间,以毫秒为单位的
                watcher:监视器对象
            */
            zooKeeper = new ZooKeeper("192.168.64.132:2181", 50000, new Watcher() {
                @Override
                public void process(WatchedEvent watchedEvent) {
                    if (watchedEvent.getState() == Event.KeeperState.SyncConnected) {
                        System.out.println("zookeeper异步连接成功");
                    } else if (watchedEvent.getState() == Event.KeeperState.Disconnected) {
                        System.out.println("断开连接");
                    } else if (watchedEvent.getState() == Event.KeeperState.Expired) {
                        System.out.println("会话超时");
                    } else if (watchedEvent.getState() == Event.KeeperState.AuthFailed) {
                        System.out.println("认证失败");
                    } else if (watchedEvent.getState() == Event.KeeperState.Closed) {
                        System.out.println("连接关闭");
                    }
                    countDownLatch.countDown();
                    System.out.println("使用构造函数默认的watcher");
                    System.out.println("path=" + watchedEvent.getPath());
                    System.out.println("eventType=" + watchedEvent.getType());
                }
            });
            // 主线程阻塞等待连接对象的创建成功
            countDownLatch.await();
            // 会话编号
            System.out.println("客户端sessionId:" + zooKeeper.getSessionId());
            return zooKeeper;
        } catch (Exception e) {
            System.out.println("zookeeper连接异常");
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 关闭zookeeper会话
     */
    public static void close() {
        if (zooKeeper != null) {
            try {
                zooKeeper.close();
                System.out.println("zookeeper关闭成功");
            } catch (InterruptedException e) {
                System.out.println("zookeeper关闭失败");
                e.printStackTrace();
            }
        }
    }
}
package com.huazai.zookeeper.zkexample.config;

import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.ZooKeeper;
import org.junit.Test;

import java.util.concurrent.TimeUnit;

/**
 * @author pyh
 * @date 2021/6/7 22:18
 */
public class ConfigCenter implements Watcher {
    private ZooKeeper zooKeeper;

    ConfigCenter configCenter;

    private DBInfo dbInfo;

    public ConfigCenter() {
        // 1.初始化连接对象
        zooKeeper = ZookeeperConnection.connect();
    }

    /**
     * 3.当zookeeper中的配置信息发生变化时,通过watcher的回调方法捕获数据变化事件
     *
     * @param event
     */
    @Override
    public void process(WatchedEvent event) {
        try {
            // 4.回调中重新获取配置信息,并注册新的监听事件
            System.out.println("监听到数据源发生改变,正在获取最新配置信息...");
            initValue();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Test
    public void test() throws Exception {
        configCenter = new ConfigCenter();
        // 1.模拟程序启动的时候第一遍获取数据源
        configCenter.initValue();

        TimeUnit.SECONDS.sleep(100);
    }

    /**
     * 2.初始化数据源存入本地变量,并注册监听器
     */
    private DBInfo initValue() throws Exception {
        String url = getData("/config/url", this);
        String username = getData("/config/username", this);
        String password = getData("/config/password", this);
        dbInfo = new DBInfo(url, username, password);
        System.out.println(dbInfo);
        return dbInfo;
    }

    private String getData(final String path, Watcher watcher) throws Exception {
        String data = new String(zooKeeper.getData(path, watcher, null));
        return data;
    }
}

class DBInfo {
    private String url;
    private String username;
    private String password;

    public DBInfo() {
    }

    public DBInfo(String url, String username, String password) {
        this.url = url;
        this.username = username;
        this.password = password;
    }

    public String getUrl() {
        return url;
    }

    public void setUrl(String url) {
        this.url = url;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    @Override
    public String toString() {
        return "DBInfo{" +
                "url='" + url + '\'' +
                ", username='" + username + '\'' +
                ", password='" + password + '\'' +
                '}';
    }
}

成功启动程序后,分别执行以下命令,修改/config/password节点数据:

set /config/password "111111"
set /config/password "888888"
set /config/password "666666"

程序控制台输出结果如下:

zookeeper配置service zookeeper配置中心怎么配置_java