先是封装的 zkClient
public class ZkClient {
public Logger logger = LoggerFactory.getLogger(getClass());
public ZooKeeper zookeeper;
private static int SESSION_TIME_OUT = 2000;
private IWatchEvent watchEvent;
private static CountDownLatch countDownLatch = new CountDownLatch(1);
private SessionWatcher sessionWatcher = new SessionWatcher();
public ZkClient(){
}
public ZkClient(IWatchEvent we){
this.watchEvent = we;
}
/**
* 连接zookeeper
* @param host
* @throws IOException
* @throws InterruptedException
*/
public void connectZookeeper(String host){
logger.info(Log.op("连接ZooKeeper开始").kv("host:", host).toString());
try {
zookeeper = new ZooKeeper(host, SESSION_TIME_OUT, sessionWatcher);
//连接超时4S
countDownLatch.await(4000, TimeUnit.MILLISECONDS);
} catch (Exception e) {
logger.error(Log.op("连接ZooKeeper异常").kv("host:", host).toString(), e);
}
logger.info(Log.op("连接ZooKeeper完成").kv("host:", host).toString());
}
class SessionWatcher implements Watcher {
public void process(WatchedEvent watchedEvent) {
logger.info(Log.op("zookeeper事件")
.kv("state:", watchedEvent.getState()).kv("type:", watchedEvent.getType()).toString());
if(watchedEvent.getState() == Event.KeeperState.SyncConnected){
countDownLatch.countDown();
}
if (watchEvent != null){
watchEvent.watchAfter(watchedEvent);
}
}
}
/**
* 根据路径创建节点,并且设置节点数据
* @param path
* @param data
* @return
* @throws KeeperException
* @throws InterruptedException
*/
public String createNode(String path,byte[] data){
logger.info(Log.op("创建ZooKeeper节点").kv("nodePath:", path).kv("data:", data).toString());
String s = null;
try {
s = this.zookeeper.create(path, data, ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
} catch (Exception e) {
logger.error(Log.op("创建ZooKeeper节点异常").kv("nodePath:", path).kv("data:", data).toString(), e);
}
return s;
}
/**
* 节点是否存在
* @param path
* @return
* @throws KeeperException
* @throws InterruptedException
*/
public boolean exists(String path) {
boolean bl = false;
try {
if (this.zookeeper.exists(path, true) != null) {
bl = true;
}
} catch (Exception e) {
logger.error(Log.op("判断zookeeper节点是否存在异常").toString(), e);
}
return bl;
}
/**
* 为节点设置监听
* @param path
* @throws KeeperException
* @throws InterruptedException
*/
public void existsWatch(String path) {
try {
this.zookeeper.exists(path, sessionWatcher);
} catch (Exception e) {
logger.error(Log.op("设置ZooKeeper节点监听异常").kv("nodePath:", path).toString(), e);
}
}
/**
* 关闭zookeeper连接
* @throws InterruptedException
*/
public void closeConnect() {
if(null != zookeeper){
try {
zookeeper.close();
} catch (InterruptedException e) {
logger.error(Log.op("关闭zookeeper连接异常").toString(), e);
}
}
}
}
只是简单是写了些自己要用到的操作,
接口 IWatchEvent 用来在watch事件执行个性化操作
public interface IWatchEvent {
void watchAfter(WatchedEvent watchedEvent);
}
最后是关键的ZkConfig类
@Configuration
public class ZkConfig {
@Value("${zookeeper.host}")
private String host;
@Value("${zookeeper.nodePath.rule}")
private String nodePath;
public Logger logger = LoggerFactory.getLogger(getClass());
private ZkClient client = null;
@Resource
DroolsHelperService droolsHelperService;
class CusWatcherEvent implements IWatchEvent{
@Override
public void watchAfter(WatchedEvent watchedEvent) {
try {
if (watchedEvent.getType() == Watcher.Event.EventType.NodeDataChanged){
logger.info(Log.op("ZooKeeper节点数据变化").kv("nodePath:", nodePath).toString());
droolsHelperService.loadRule();
}
//失效重连
if (watchedEvent.getState() == Watcher.Event.KeeperState.Expired) {
client.closeConnect();
client.connectZookeeper(host);
}
} catch (Exception e) {
logger.error(Log.op("加载规则异常").kv("nodePath:", nodePath).toString(), e);
}finally {
logger.info(Log.op("重新监听ZooKeeper节点").kv("nodePath:", nodePath).toString());
client.existsWatch(nodePath);
}
}
}
/**
* 添加zk节点监听
*/
@PostConstruct
private void init(){
client = new ZkClient(new CusWatcherEvent());
client.connectZookeeper(host);
byte[] bytes = new byte[]{1};
if (!client.exists(nodePath)) {
client.createNode(nodePath, bytes);
}else{
logger.info(Log.op("ZooKeeper节点已存在").kv("nodePath:", nodePath).toString());
}
}
}
watch 是一次性监听,所以每次都注册新的监听