package com.github.ltsopensource.core.registry.zookeeper; import com.github.ltsopensource.core.AppContext; import com.github.ltsopensource.core.cluster.Node; import com.github.ltsopensource.core.cluster.NodeType; import com.github.ltsopensource.core.commons.utils.CollectionUtils; import com.github.ltsopensource.core.registry.FailbackRegistry; import com.github.ltsopensource.core.registry.NodeRegistryUtils; import com.github.ltsopensource.core.registry.NotifyEvent; import com.github.ltsopensource.core.registry.NotifyListener; import com.github.ltsopensource.core.spi.ServiceLoader; import com.github.ltsopensource.zookeeper.ChildListener; import com.github.ltsopensource.zookeeper.StateListener; import com.github.ltsopensource.zookeeper.ZkClient; import com.github.ltsopensource.zookeeper.ZookeeperTransporter; import java.util.ArrayList; import java.util.List; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; /** * @author Robert HG (254963746@qq.com) on 6/22/14. * 节点注册器,并监听自己关注的节点 */ public class ZookeeperRegistry extends FailbackRegistry { private ZkClient zkClient; // 用来记录父节点下的子节点的变化 private final ConcurrentHashMap<String/*parentPath*/, List<String/*children*/>> cachedChildrenNodeMap; private final ConcurrentMap<Node, ConcurrentMap<NotifyListener, ChildListener>> zkListeners; private String clusterName; public ZookeeperRegistry(final AppContext appContext) { super(appContext); this.clusterName = appContext.getConfig().getClusterName(); this.cachedChildrenNodeMap = new ConcurrentHashMap<String, List<String>>(); ZookeeperTransporter zookeeperTransporter = ServiceLoader.load(ZookeeperTransporter.class, appContext.getConfig()); this.zkClient = zookeeperTransporter.connect(appContext.getConfig()); this.zkListeners = new ConcurrentHashMap<Node, ConcurrentMap<NotifyListener, ChildListener>>(); // 默认是连成功的(用zkclient时候,第一次不会有state changed事件暴露给用户, // 他居然在new ZkClient的时候就直接连接了,给个提供listener的构造函数或者把启动改为start方法都ok呀,蛋疼) appContext.getRegistryStatMonitor().setAvailable(true); zkClient.addStateListener(new StateListener() { @Override public void stateChanged(int state) { if (state == DISCONNECTED) { appContext.getRegistryStatMonitor().setAvailable(false); } else if (state == CONNECTED) { appContext.getRegistryStatMonitor().setAvailable(true); } else if (state == RECONNECTED) { try { appContext.getRegistryStatMonitor().setAvailable(true); recover(); } catch (Exception e) { LOGGER.error(e.getMessage(), e); } } } }); } @Override protected void doRegister(Node node) { if (zkClient.exists(node.toFullString())) { return; } zkClient.create(node.toFullString(), true, false); } @Override protected void doUnRegister(Node node) { zkClient.delete(node.toFullString()); } @Override protected void doSubscribe(Node node, NotifyListener listener) { List<NodeType> listenNodeTypes = node.getListenNodeTypes(); if (CollectionUtils.isEmpty(listenNodeTypes)) { return; } for (NodeType listenNodeType : listenNodeTypes) { String listenNodePath = NodeRegistryUtils.getNodeTypePath(clusterName, listenNodeType); ChildListener zkListener = addZkListener(node, listener); // 为自己关注的 节点 添加监听 List<String> children = zkClient.addChildListener(listenNodePath, zkListener); if (CollectionUtils.isNotEmpty(children)) { List<Node> listenedNodes = new ArrayList<Node>(); for (String child : children) { Node listenedNode = NodeRegistryUtils.parse(listenNodePath + "/" + child); listenedNodes.add(listenedNode); } notify(NotifyEvent.ADD, listenedNodes, listener); cachedChildrenNodeMap.put(listenNodePath, children); } } } @Override protected void doUnsubscribe(Node node, NotifyListener listener) { ConcurrentMap<NotifyListener, ChildListener> listeners = zkListeners.get(node); if (listeners != null) { ChildListener zkListener = listeners.get(listener); if (zkListener != null) { List<NodeType> listenNodeTypes = node.getListenNodeTypes(); if (CollectionUtils.isEmpty(listenNodeTypes)) { return; } for (NodeType listenNodeType : listenNodeTypes) { String listenNodePath = NodeRegistryUtils.getNodeTypePath(clusterName, listenNodeType); zkClient.removeChildListener(listenNodePath, zkListener); } } } } private ChildListener addZkListener(Node node, final NotifyListener listener) { ConcurrentMap<NotifyListener, ChildListener> listeners = zkListeners.get(node); if (listeners == null) { zkListeners.putIfAbsent(node, new ConcurrentHashMap<NotifyListener, ChildListener>()); listeners = zkListeners.get(node); } ChildListener zkListener = listeners.get(listener); if (zkListener == null) { listeners.putIfAbsent(listener, new ChildListener() { public void childChanged(String parentPath, List<String> currentChildren) { if (CollectionUtils.isEmpty(currentChildren)) { currentChildren = new ArrayList<String>(0); } List<String> oldChildren = cachedChildrenNodeMap.get(parentPath); // 1. 找出增加的 节点 List<String> addChildren = CollectionUtils.getLeftDiff(currentChildren, oldChildren); // 2. 找出减少的 节点 List<String> decChildren = CollectionUtils.getLeftDiff(oldChildren, currentChildren); if (CollectionUtils.isNotEmpty(addChildren)) { List<Node> nodes = new ArrayList<Node>(addChildren.size()); for (String child : addChildren) { Node node = NodeRegistryUtils.parse(parentPath + "/" + child); nodes.add(node); } ZookeeperRegistry.this.notify(NotifyEvent.ADD, nodes, listener); } if (CollectionUtils.isNotEmpty(decChildren)) { List<Node> nodes = new ArrayList<Node>(addChildren.size()); for (String child : decChildren) { Node node = NodeRegistryUtils.parse(parentPath + "/" + child); nodes.add(node); } ZookeeperRegistry.this.notify(NotifyEvent.REMOVE, nodes, listener); } cachedChildrenNodeMap.put(parentPath, currentChildren); } }); zkListener = listeners.get(listener); } return zkListener; } @Override public void destroy() { super.destroy(); try { zkClient.close(); } catch (Exception e) { LOGGER.warn("Failed to close zookeeper client " + getNode() + ", cause: " + e.getMessage(), e); } } }