Druid10-ZK动态配置数据源

1、ZooKeeper 注册数据源

​ 通过创建 ZooKeeper 的临时节点,以此实现节点发现和下线,实现动态变更数据源信息,使用案例。

   private void register() {
       	//创建注册对象
        ZookeeperNodeRegister register1 = new ZookeeperNodeRegister();
        register1.setZkConnectString("127.0.0.1:2181");
        register1.init();
        ZookeeperNodeRegister register2 = new ZookeeperNodeRegister();
        register2.setZkConnectString("127.0.0.1:2181");
        register2.init();
		
       	//配置数据源信息
        ZookeeperNodeInfo node = new ZookeeperNodeInfo();
        node.setHost("localhost");
        node.setPort(3306);
        node.setPrefix("NodeToo");
        node.setDatabase(DATA_BASE);
        node.setUsername(USER_NAME);
        node.setPassword(PASSWORD);
        ZookeeperNodeInfo node1 = new ZookeeperNodeInfo();
        node1.setHost("127.0.0.1");
        node1.setPort(3306);
        node1.setPrefix("NodeToo");
        node1.setDatabase(DATA_BASE);
        node1.setUsername(USER_NAME);
        node1.setPassword(PASSWORD);

        //数据注册
        register1.register("Node1", Collections.singletonList(node));
        register2.register("Node2", Collections.singletonList(node1));
	}

   //配置高可用数据源节点监听器
	public void haDataSource(){
        HighAvailableDataSource haDataSource = new HighAvailableDataSource();
        ZookeeperNodeListener listener = new ZookeeperNodeListener();
        listener.setZkConnectString("127.0.0.1:2181");
        listener.setPath("/ha-druid-datasources");
        listener.setPrefix("NodeToo");
        listener.setUrlTemplate("jdbc:mysql://${host}:${port}/${database}?useUnicode=true");
        haDataSource.setNodeListener(listener);
    }
2、ZookeeperNodeRegister

​ ZookeeperNodeRegister 将配置信息进行注册。

    //初始化连接
	public void init() {
        //创建Zk客户端
        if (client == null) {
            client = CuratorFrameworkFactory.builder()
                	//设置连接超时时间
                    .connectionTimeoutMs(5000)
                	//设置连接地址
                    .connectString(zkConnectString)
                    .retryPolicy(new RetryForever(10000))
                	//会话超时时间
                    .sessionTimeoutMs(30000)
                    .build();
            //启动客户端
            client.start();
            privateZkClient = true;
        }
    }

	//服务注册
    public boolean register(String nodeId, List<ZookeeperNodeInfo> payload) {
        if (payload == null || payload.isEmpty()) {
            return false;
        }
        try {
            lock.lock();
            //路径不存在则创建
            createPathIfNotExisted();
            //判断是否已经注册
            if (member != null) {
                LOG.warn("GroupMember has already registered. Please deregister first.");
                return false;
            }
            //将配置信息转换成String
            String payloadString = getPropertiesString(payload);
            //设置临时节点ID,配置数据转成字节
            member = new GroupMember(client, path, nodeId, payloadString.getBytes());
            //创建临时节点
            member.start();
            LOG.info("Register Node["+ nodeId + "] in path[" + path + "].");
            return true;
        } finally {
            lock.unlock();
        }
    }
3、ZookeeperNodeListener

​ 通过对ZookeeperNodeListener 监听事件的变更,实现数据源配置的动态更新。

   public void init() {
        checkParameters();
        super.init();
        if (client == null) {
            //创建客户端
            client = CuratorFrameworkFactory.builder()
                    .canBeReadOnly(true)
                    .connectionTimeoutMs(5000)
                    .connectString(zkConnectString)
                    .retryPolicy(new RetryForever(10000))
                    .sessionTimeoutMs(30000)
                    .build();
            //启动客户端
            client.start();
            privateZkClient = true;
        }
       	//true表示把节点内容缓存
        cache = new PathChildrenCache(client, path, true);
        //添加缓存监听器
        cache.getListenable().addListener(new PathChildrenCacheListener() {
            @Override
            public void childEvent(CuratorFramework client, PathChildrenCacheEvent event) throws Exception {
                try {
                    LOG.info("Receive an event: " + event.getType());
                    lock.lock();
                    PathChildrenCacheEvent.Type eventType = event.getType();
                    switch (eventType) {
                        //删除事件
                        case CHILD_REMOVED:
                            //事件类型是删除
                            updateSingleNode(event, NodeEventTypeEnum.DELETE);
                            break;
                         //新增事件
                        case CHILD_ADDED:
                            //事件类型是添加
                            updateSingleNode(event, NodeEventTypeEnum.ADD);
                            break;
                        //重新连接事件
                        case CONNECTION_RECONNECTED:
                            refreshAllNodes();
                            break;
                        default:
                            LOG.info("Received a PathChildrenCacheEvent, IGNORE it: " + event);
                    }
                } finally {
                    lock.unlock();
                    LOG.info("Finish the processing of event: " + event.getType());
                }
            }
        });
        try {
            //强制在当前线程中构建缓存
            cache.start(PathChildrenCache.StartMode.BUILD_INITIAL_CACHE);
        } catch (Exception e) {
            LOG.error("Can't start PathChildrenCache", e);
        }
    }
	//更新所有节点
    private void refreshAllNodes() {
        try {
            //判断路径是否存在
            if (client.checkExists().forPath(path) == null) {
                LOG.warn("PATH[" + path + "] is NOT existed, can NOT refresh nodes.");
                return;
            }
            //重建缓存数据
            cache.rebuild();
            //获取所有的配置信息
            Properties properties = getPropertiesFromCache();
            //将配置数据转换成Event对象
            List<NodeEvent> events = NodeEvent.getEventsByDiffProperties(getProperties(), properties);
            if (events != null && !events.isEmpty()) {
                setProperties(properties);
                //被监视者对象变更,通过父类方法通知观察者对象
                super.update(events);
            }
        } catch (Exception e) {
            LOG.error("Can NOT refresh Cache Nodes.", e);
        }
    }
	//数据变更节点
    private void updateSingleNode(PathChildrenCacheEvent event, NodeEventTypeEnum type) {
        //获得变更数据
        ChildData data = event.getData();
        //节点名称
        String nodeName = getNodeName(data);
        List<String> names = new ArrayList<String>();
        //匹配前缀
        names.add(getPrefix() + "." + nodeName);
        //数据转成配置数据
        Properties properties = getPropertiesFromChildData(data);
        //将配置数据转成变更对象
        List<NodeEvent> events = NodeEvent.generateEvents(properties, names, type);
        if (events.isEmpty()) {
            return;
        }
        if (type == NodeEventTypeEnum.ADD) {
            //将变更数据添加到集合
            getProperties().putAll(properties);
        } else {
            for (String n : properties.stringPropertyNames()) {
                getProperties().remove(n);
            }
        }
        //被监视者对象变更,通过父类方法通知观察者对象
        super.update(events);
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值