内容提要:
1、zookeeper注册中心依赖
2、zookeeper实现注册中心原理。节点、临时节点、watch机制。
3、利用watch实现注册中心。客户端、服务端使用注册中心不同的能力。
一、首先添加依赖
org.apache.zookeeper
zookeeper
3.4.5
javax.jms
jms
com.sun.jdmk
jmxtools
com.sun.jmx
jmxri
com.github.sgroschupf
zkclient
0.1
2、zk API简单应用展示
package com.cloudwise.registy.zk;
import javax.swing.plaf.synth.SynthSpinnerUI;
import org.I0Itec.zkclient.IZkDataListener;
import org.I0Itec.zkclient.ZkClient;
/**
*
* Title: TestZookeeper 测试zkclient功能代码
* Description:
* @author back
* @date 2019年8月17日
*/
public class TestZookeeper {
public static void main(String[] args) throws InterruptedException {
String addr = "192.168.231.135:2181";
int connectionTimeout = 3000;
ZkClient zkClient = new ZkClient(addr, connectionTimeout);
String path = "/zk-data";
boolean flag = zkClient.exists(path);
if(flag)
zkClient.delete(path);
//创建永久节点
zkClient.createPersistent(path);
//节点下写入数据
zkClient.writeData(path, "zk store data");
//读取节点下数据
String data = zkClient.readData(path, true);
System.out.println("读取数据 : "+data);
zkClient.subscribeDataChanges(path, new IZkDataListener() {
@Override
public void handleDataDeleted(String dataPath) throws Exception {
System.out.println("节点数据删除 !");
}
@Override
public void handleDataChange(String dataPath, Object data) throws Exception {
System.out.println("节点数据更改");
}
});
zkClient.writeData(path, "zk store data new");
zkClient.delete(path);
Thread.sleep(Integer.MAX_VALUE);
}
}
3、注册中心代码封装
1、服务端注册中心接口能力
/**
* 服务端注册中心
* Title: IRegisterCenter4Provider.java
* Description:
* @author zhaojunjie
* @date 2020年3月28日
* @version 1.0
*/
public interface IRegisterCenter4Provider {
/**
* 提供者信息注册到zk节点下
* @param serviceMetaData
*/
public void registerProvider(final List serviceMetaData);
/**
* 服务端获取提供者信息
* @return
*/
public Map> getProviderServiceMap();
}
2、客户端注册中心接口能力
/**
* 代表客户端注册中心能力接口
* Title: IRegisterCenter4Invoker.java
* Description:
* @author zhaojunjie
* @date 2020年3月28日
* @version 1.0
*/
public interface IRegisterCenter4Invoker {
/**
* 客户端初始化服务提供者基本信息
*/
public void initProviderMap();
/**
* 客户端获取服务端提供者信息
* @return
*/
public Map> getServiceMetaDataMap4Consume();
/**
* 消费端将缴费者信息注册到zk节点下
* @param invok
*/
public void registerInvoker(final InvokerService invokerService);
}
3、注册中心实现
public class RegisterCenter implements IRegisterCenter4Invoker, IRegisterCenter4Provider{
private static RegisterCenter registerCenter = new RegisterCenter();
//key:接口 value:方法
private static final Map> providerServiceMap = new ConcurrentHashMap<>();
//zk同步的信息
private static final Map> serviceMetaDataMap4Consume = new ConcurrentHashMap>();
private static String ZK_SERVICE = PropertyHelper.getProperty("zookeeper", String.class);
private static int ZK_SESSION_TIMEOUT = 3000;
private static int ZK_CONNECT_TIMEOUT = 3000;
private static String ROOT_PATH = "/back_register";
private static String PROVIDER_TYPE = "/provider";
private static String INVOKER_TYPE = "/consumer";
private static volatile ZkClient zkClient = null;
private RegisterCenter(){}
public static RegisterCenter singleton(){
return registerCenter;
}
@Override
public void registerProvider(List serviceMetaData) {
if(serviceMetaData == null){
return;
}
//连接zk 注册服务
synchronized (RegisterCenter.class) {
for (ProviderService providerService : serviceMetaData) {
String serviceKey = providerService.getServiceInterface().getName();
List list = providerServiceMap.get(serviceKey);
if(list == null){
list = new ArrayList();
}
list.add(providerService);
providerServiceMap.put(serviceKey, list);
}
if(zkClient == null){
zkClient = new ZkClient(ZK_SERVICE, ZK_SESSION_TIMEOUT,
ZK_CONNECT_TIMEOUT, new SerializableSerializer());
}
boolean exists = zkClient.exists(ROOT_PATH);
if(!exists){
zkClient.createPersistent(ROOT_PATH, true);
}
for (Entry> entry : providerServiceMap.entrySet()) {
String serviceNode = entry.getKey();
String basePath = ROOT_PATH + "/" + serviceNode;
String servicePath = ROOT_PATH + "/" + serviceNode + PROVIDER_TYPE;
exists = zkClient.exists(basePath);
if(!exists){
zkClient.createPersistent(basePath);
}
exists = zkClient.exists(servicePath);
if(!exists){
zkClient.createPersistent(servicePath);
}
int servicePort = entry.getValue().get(0).getServicePort();
String ip = IPHelper.getCurrentIp();
String currentServiceIpNode = servicePath + "/" + ip + "|" + servicePort;
exists = zkClient.exists(currentServiceIpNode);
if(!exists){
zkClient.createEphemeral(currentServiceIpNode);
}
zkClient.subscribeChildChanges(servicePath, new IZkChildListener() {
@Override
public void handleChildChange(String parentPath, List currentChilds) throws Exception {
if(currentChilds == null){
currentChilds = new ArrayList<>();
}
List transform = Lists.transform(currentChilds, new Function() {
@Override
public String apply(String input) {
return org.apache.commons.lang3.StringUtils.split(input, "|")[0];
}
});
refreshActivityService(transform);
}
});
}
}
}
/**
* 服务端刷新服务列表
*/
private void refreshActivityService(List serviceIpList) {
if(serviceIpList == null){
serviceIpList = Lists.newArrayList();
}
Map> currentServiceMetaDataMap = Maps.newHashMap();
for (Entry> entry : providerServiceMap.entrySet()) {
String key = entry.getKey();
List providerServices = entry.getValue();
List serviceMetaDataModelList = currentServiceMetaDataMap.get(key);
if(serviceMetaDataModelList == null){
serviceMetaDataModelList = Lists.newArrayList();
}
for (ProviderService providerService : providerServices) {
if(serviceIpList.contains(providerService.getServerIp())){
serviceMetaDataModelList.add(providerService);
}
}
currentServiceMetaDataMap.put(key, serviceMetaDataModelList);
}
providerServiceMap.putAll(currentServiceMetaDataMap);
}
/**
* 客户端刷新列表
* @param transform
*/
private void refreshServiceMetaDataMap(List serviceIpList) {
if(serviceIpList == null){
serviceIpList = Lists.newArrayList();
}
Map> currentServiceMetaDataMap = Maps.newHashMap();
for (Entry> entry : serviceMetaDataMap4Consume.entrySet()) {
String key = entry.getKey();
List serviceList = entry.getValue();
List providerServiceList = currentServiceMetaDataMap.get(key);
if(providerServiceList == null){
providerServiceList = Lists.newArrayList();
}
for (ProviderService providerService : serviceList) {
if(serviceIpList.contains(providerService.getServerIp())){
providerServiceList.add(providerService);
}
}
currentServiceMetaDataMap.put(key, providerServiceList);
}
serviceMetaDataMap4Consume.putAll(currentServiceMetaDataMap);
System.out.println("serviceMetaDataMap4Consume : " + JsonUtils.writeToString(serviceMetaDataMap4Consume));
}
/**
* 获得服务信息
* @return
*/
private Map> fetchorUpdateServiceMetaData() {
Map> providerServiceMap = Maps.newConcurrentMap();
synchronized (RegisterCenter.class) {
if(zkClient == null){
zkClient = new ZkClient(ZK_SERVICE, ZK_SESSION_TIMEOUT,
ZK_CONNECT_TIMEOUT, new SerializableSerializer());
}
String providerPath = ROOT_PATH;
List providerServices = zkClient.getChildren(providerPath);
for (String serviceName : providerServices) {
String servicePath = providerPath + "/" + serviceName + PROVIDER_TYPE;
List ipList = zkClient.getChildren(servicePath);
for (String ipPath : ipList) {
String serverIp = org.apache.commons.lang3.StringUtils.split(ipPath, "|")[0];
String serverPort = org.apache.commons.lang3.StringUtils.split(ipPath, "|")[1];
List providerServiceList = providerServiceMap.get(serviceName);
if(providerServiceList == null){
providerServiceList = Lists.newArrayList();
}
ProviderService providerService = new ProviderService();
try {
providerService.setServiceInterface(ClassUtils.getClass(serviceName));
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
}
providerService.setServerIp(serverIp);
providerService.setServicePort(Integer.parseInt(serverPort));
providerServiceList.add(providerService);
providerServiceMap.put(serviceName, providerServiceList);
}
zkClient.subscribeChildChanges(servicePath, new IZkChildListener() {
@Override
public void handleChildChange(String parentPath, List currentChilds) throws Exception {
if(currentChilds == null){
currentChilds = Lists.newArrayList();
}
List transform = Lists.transform(currentChilds, new Function() {
@Override
public String apply(String input) {
return org.apache.commons.lang3.StringUtils.split(input, "|")[0];
}
});
refreshServiceMetaDataMap(transform);
}
});
}
}
return providerServiceMap;
}
@Override
public Map> getProviderServiceMap() {
return providerServiceMap;
}
@Override
public void initProviderMap() {
if(MapUtils.isEmpty(serviceMetaDataMap4Consume)){
serviceMetaDataMap4Consume.putAll(fetchorUpdateServiceMetaData());
}
}
@Override
public Map> getServiceMetaDataMap4Consume() {
return serviceMetaDataMap4Consume;
}
@Override
public void registerInvoker(InvokerService invokerService) {
if(invokerService == null){
return;
}
synchronized (RegisterCenter.class) {
if(zkClient == null){
zkClient = new ZkClient(ZK_SERVICE, ZK_SESSION_TIMEOUT,
ZK_CONNECT_TIMEOUT, new SerializableSerializer());
}
boolean exists = zkClient.exists(ROOT_PATH);
if(!exists){
zkClient.createPersistent(ROOT_PATH, true);
}
String serviceNode = invokerService.getTargetInterface().getName();
String servicePath = ROOT_PATH + "/" + serviceNode + INVOKER_TYPE;
exists = zkClient.exists(servicePath);
if(!exists){
zkClient.createPersistent(servicePath);
}
String ip = IPHelper.getCurrentIp();
String currentServiceIpNode = servicePath + "/" + ip;
exists = zkClient.exists(currentServiceIpNode);
if(!exists){
zkClient.createEphemeral(currentServiceIpNode);
}
}
}
}