通过创建 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);
}
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();
}
}
通过对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);
}