All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.xxl.conf.core.XxlConfZkClient Maven / Gradle / Ivy

package com.xxl.conf.core;

import com.xxl.conf.core.util.Environment;
import org.apache.zookeeper.*;
import org.apache.zookeeper.data.Stat;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;


/**
 * ZooKeeper cfg client (Watcher + some utils)
 * @author xuxueli 2015年8月26日21:36:43
 *
 *         Zookeeper
 *         从设计模式角度来看,是一个基于观察者模式设计的分布式服务管理框架,它负责存储和管理大家都关心的数据,然后接受观察者的注册
 *         ,一旦这些数据的状态发生变化,Zookeeper 就将负责通知已经在 Zookeeper
 *         上注册的那些观察者做出相应的反应,从而实现集群中类似 Master/Slave 管理模式
 *
 *         1、统一命名服务(Name Service):将有层次的目录结构关联到一定资源上,广泛意义上的关联,也许你并不需要将名称关联到特定资源上,
 *         你可能只需要一个不会重复名称。
 *
 *         2、配置管理(Configuration Management):分布式统一配置管理:将配置信息保存在
 *         Zookeeper 的某个目录节点中,然后将所有需要修改的应用机器监控配置信息的状态,一旦配置信息发生变化,每台应用机器就会收到
 *         Zookeeper 的通知,然后从 Zookeeper 获取新的配置信息应用到系统中
 *
 *         3、集群管理(Group
 *         Membership):Zookeeper 能够很容易的实现集群管理的功能,如有多台 Server 组成一个服务集群,那么必须
 *         要一个“总管”知道当前集群中每台机器的服务状态,一旦有机器不能提供服务,集群中其它集群必须知道,从而做出调整重新分配服务策略。
 *         同样当增加集群的服务能力时,就会增加一台或多台 Server,同样也必须让“总管”知道。
 *
 *         4、共享锁(Locks):
 *         5、队列管理:a、当一个队列的成员都聚齐时,这个队列才可用,否则一直等待所有成员到达,这种是同步队列。b、队列按照 FIFO 方式
 *         进行入队和出队操作,例如实现生产者和消费者模型。
 *
 *         集中式配置管理 动态更新
 *
 */
public class XxlConfZkClient implements Watcher {
	private static Logger logger = LoggerFactory.getLogger(XxlConfZkClient.class);

	// ------------------------------ zookeeper client ------------------------------
	private static ZooKeeper zooKeeper;
	private static ReentrantLock INSTANCE_INIT_LOCK = new ReentrantLock(true);
	private static ZooKeeper getInstance(){
		if (zooKeeper==null) {
			try {
				if (INSTANCE_INIT_LOCK.tryLock(2, TimeUnit.SECONDS)) {
					try {
						zooKeeper = new ZooKeeper(Environment.ZK_ADDRESS, 20000, new Watcher() {
							@Override
							public void process(WatchedEvent watchedEvent) {
								try {
									logger.info(">>>>>>>>>> xxl-conf: 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) {
											XxlConfClient.remove(key);
										} else if (watchedEvent.getType() == Event.EventType.NodeDataChanged) {
											String data = getPathDataByKey(key);
											XxlConfClient.update(key, data);
										}
									}
								} catch (KeeperException e) {
									e.printStackTrace();
								} catch (InterruptedException e) {
									e.printStackTrace();
								}
							}
						});
						XxlConfZkClient.createWithParent(Environment.CONF_DATA_PATH);	// init cfg root path
					} finally {
						INSTANCE_INIT_LOCK.unlock();
					}
                }
			} catch (InterruptedException e) {
				e.printStackTrace();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		if (zooKeeper == null) {
			throw new NullPointerException(">>>>>>>>>>> xxl-cache, XxlConfZkClient.zooKeeper is null.");
		}
		return zooKeeper;
	}

	/**
	 * 监控所有被触发的事件(One-time trigger)
	 */
	@Override
	public void process(WatchedEvent event) {

	}

	// ------------------------------ util ------------------------------
	/**
	 * path 2 key
	 * @param nodePath
	 * @return ZnodeKey
	 */
	private static String pathToKey(String nodePath){
		if (nodePath==null || nodePath.length() <= Environment.CONF_DATA_PATH.length() || !nodePath.startsWith(Environment.CONF_DATA_PATH)) {
			return null;
		}
		return nodePath.substring(Environment.CONF_DATA_PATH.length()+1, nodePath.length());
	}

	/**
	 * key 2 path
	 * @param nodeKey
	 * @return znodePath
	 */
	private static String keyToPath(String nodeKey){
		return Environment.CONF_DATA_PATH + "/" + nodeKey;
	}

	public static String generateGroupKey(String nodeGroup, String nodeKey){
		return nodeGroup + "." + nodeKey;
	}

	/**
	 * create node path with parent path (如果父节点不存在,循环创建父节点, 因为父节点不存在zookeeper会抛异常)
	 * @param path	()
	 */
	private static Stat createWithParent(String path){
		// valid
		if (path==null || path.trim().length()==0) {
			return null;
		}

		try {
			Stat stat = getInstance().exists(path, true);
			if (stat == null) {
				//  valid parent, createWithParent if not exists
				if (path.lastIndexOf("/") > 0) {
					String parentPath = path.substring(0, path.lastIndexOf("/"));
					Stat parentStat = getInstance().exists(parentPath, true);
					if (parentStat == null) {
						createWithParent(parentPath);
					}
				}
				// create desc node path
				zooKeeper.create(path, new byte[]{}, ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
			}
			return getInstance().exists(path, true);
		} catch (KeeperException e) {
			e.printStackTrace();
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		return null;
	}

	/**
	 * delete path by key
	 * @param key
	 */
	public static void deletePathByKey(String key){
		String path = keyToPath(key);
		try {
			Stat stat = getInstance().exists(path, true);
			if (stat != null) {
				getInstance().delete(path, stat.getVersion());
			} else {
				logger.info(">>>>>>>>>> zookeeper node path not found :{}", key);
			}
		} catch (KeeperException e) {
			e.printStackTrace();
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}

	/**
	 * set data to node
	 * @param key
	 * @param data
	 * @return
	 */
	public static Stat setPathDataByKey(String key, String data) {
		String path = keyToPath(key);
		try {
			Stat stat = getInstance().exists(path, true);
			if (stat == null) {
				createWithParent(path);
				stat = getInstance().exists(path, true);
			}
			return zooKeeper.setData(path, data.getBytes(),stat.getVersion());
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}

	/**
	 * get data from node
	 * @param key
	 * @return
	 */
	public static String getPathDataByKey(String key){
		String path = keyToPath(key);
		try {
			Stat stat = getInstance().exists(path, true);
			if (stat != null) {
				String znodeValue = null;
				byte[] resultData = getInstance().getData(path, true, null);
				if (resultData != null) {
					znodeValue = new String(resultData);
				}
				return znodeValue;
			} else {
				logger.info(">>>>>>>>>> znodeKey[{}] not found.", key);
			}
		} catch (KeeperException e) {
			e.printStackTrace();
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		return null;
	}

	/**
	 * 获取配置目录下所有配置
	 * @return
	 */
	private static Map getAllData(){
		Map allData = new HashMap();
		try {
			List childKeys = getInstance().getChildren(Environment.CONF_DATA_PATH, true);
			if (childKeys!=null && childKeys.size()>0) {
				for (String key : childKeys) {
					String data = getPathDataByKey(key);
					allData.put(key, data);
				}
			}
		} catch (KeeperException e) {
			e.printStackTrace();
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		return allData;
	}

	public static void main(String[] args) throws InterruptedException, KeeperException {
		setPathDataByKey("key02", "666");
		System.out.println(getPathDataByKey("key02"));

		System.out.println(getAllData());
		getInstance().delete(Environment.CONF_DATA_PATH + "/key02", -1);
		getInstance().delete(Environment.CONF_DATA_PATH, -1);

	}

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy