背景
传统的SSH架构可以分层拆分为微服务,以RPC的访问方式,替换原来的进程内调用。大量微服务需要自动注册到zookeeper、或者退出。此时服务的变化需要一些后续处理,例如根据微服务来调整API网关等。
知识点:zookeeper的Watcher机制是每次通知后便失效,需要重新注册。
注:zookeeper原生API不好用,有个curator框架做了封装,了解一下。
实现
需要用到org.apache.zookeeper:zookeeper.jar
public static void main(String[] args) {
Executors.newSingleThreadExecutor().execute(() -> {
ZooKeeperWatcher watcher = new ZooKeeperWatcher();
watcher.createConnection(ZooKeeperWatcher.CONNECTION_ADDR, ZooKeeperWatcher.SESSION_TIMEOUT);
while (true) {
}
});
}
package com.example.demo;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicInteger;
import org.apache.zookeeper.*;
import org.apache.zookeeper.Watcher.Event.EventType;
import org.apache.zookeeper.Watcher.Event.KeeperState;
import org.apache.zookeeper.ZooDefs.Ids;
import org.apache.zookeeper.data.Stat;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
/**
* Zookeeper Wathcher
* 本类就是一个Watcher类(实现了org.apache.zookeeper.Watcher类)
* @authorjeff
*/
@Component
public class ZooKeeperWatcher {
public static final int SESSION_TIMEOUT = 10000;
public static final String CONNECTION_ADDR = "192.168.1.200:2181";
public ZooKeeper zk = null;
private CountDownLatch connectedSemaphore = new CountDownLatch(1);
public void createConnection(String connectAddr, int sessionTimeout) {
this.releaseConnection();
try {
// 第一步是连接zookeeper
zk = new ZooKeeper(connectAddr, sessionTimeout, new Watcher() {
@Override
public void process(WatchedEvent event) {
if(EventType.None.getIntValue() == event.getType().getIntValue()) {
connectedSemaphore.countDown();
}
}
});
connectedSemaphore.await();
// 第二步是通过getChildren方法递归设置Watcher监听,除了getChildren还有好多方法也可以。
setWatch("/", zk);
} catch (Exception e) {
e.printStackTrace();
}
}
public void releaseConnection() {
if (this.zk != null) {
try {
this.zk.close();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
// 递归创建监听
public void setWatch(String path, ZooKeeper zk) throws Exception {
if(zk.exists(path, null) == null) {
return;
}
System.out.println("---------setWatch---------" + path);
List<String> children = zk.getChildren(path, new Watcher() {
@Override
public void process(WatchedEvent event) {
System.out.println(event.getPath() + " >>>>>>>>>" + event.getType().name());
try {
setWatch(path, zk);// 每次监听消费后,需要重新增加Watcher
} catch (Exception e) {
e.printStackTrace();
}
}
});
if(!path.endsWith("Dao")) {
for(String c : children) {
String subP = ("/".equals(path)?"":path) + "/" + c;
setWatch(subP, zk);
}
}
}
}
执行main方法后,可以使用zkCli.sh命令连接服务端
增加节点
create /path/node1 data1
删除节点
delete /path/node1
控制台会打印响应内容,证明监听成功