一、添加项目所需依赖:
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
<!-- Apache Curator 包含了几个包:
curator-client:提供一些客户端的操作,例如重试策略等
curator-framework:对zookeeper的底层api的一些封装
curator-recipes:封装了一些高级特性,如:Cache事件监听、选举、分布式锁、分布式计数器、分布式Barrier等-->
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-recipes</artifactId>
<version>2.13.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
二、连接zooKeeper 服务,使用 Client API:
@ConfigurationProperties 、@EnableConfigurationProperties 注解用来属性映射类
apache.zookeeper.connect-url=127.0.0.1:2181,127.0.0.1:2182,127.0.0.1:2183 #连接地址,此地址为单机集群;
apache.zookeeper.session-timeout=60000 #会话超时时间,默认60000ms
apache.zookeeper.connection-timeout=15000 #连接创建超时时间,默认15000ms
apache.zookeeper.scheme=digest #访问控制 验证策略
apache.zookeeper.auth-id=username:password #权限 Id
apache.retrypolicy.base-sleep-time=1000 #重连策略,初始化间隔时间
apache.retrypolicy.max-retries=3 #重连次数
apache.retrypolicy.max-sleep=2147483647 #重连最长时间
2、配置类:
@ConfigurationProperties(prefix = "apache.zookeeper")
@Configuration
public class ApacheZooKeeperProperties {
private String connectUrl;
private int sessionTimeout;
private int connectionTimeout;
private String scheme;
private String authId;
public String getConnectUrl() {
return connectUrl;
}
public void setConnectUrl(String connectUrl) {
this.connectUrl = connectUrl;
}
public int getSessionTimeout() {
return sessionTimeout;
}
public void setSessionTimeout(int sessionTimeout) {
this.sessionTimeout = sessionTimeout;
}
public int getConnectionTimeout() {
return connectionTimeout;
}
public void setConnectionTimeout(int connectionTimeout) {
this.connectionTimeout = connectionTimeout;
}
public String getScheme() {
return scheme;
}
public void setScheme(String scheme) {
this.scheme = scheme;
}
public String getAuthId() {
return authId;
}
public void setAuthId(String authId) {
this.authId = authId;
}
}
@ConfigurationProperties(prefix = "apache.retrypolicy")
@Configuration
public class ApacheRetryPolicy {
private int baseSleepTime = 1000;
private int maxRetries = 29;
private int maxSleep = 2147483647;
public int getBaseSleepTime() {
return baseSleepTime;
}
public void setBaseSleepTime(int baseSleepTime) {
this.baseSleepTime = baseSleepTime;
}
public int getMaxRetries() {
return maxRetries;
}
public void setMaxRetries(int maxRetries) {
this.maxRetries = maxRetries;
}
public int getMaxSleep() {
return maxSleep;
}
public void setMaxSleep(int maxSleep) {
this.maxSleep = maxSleep;
}
}
3、演示代码:
/**
* 演示 Apache Curator API
* 1、增删查改
* 2、ACL 访问权限控制
* 3、注册 watch 事件的三个接口
*/
@RestController
public class CuratorClientApiText {
private Logger logger = LoggerFactory.getLogger(CuratorClientApiText.class);
@Autowired
private CuratorFramework zkClient;
@Autowired
private ApacheZooKeeperProperties apacheZooKeeperProperties;
private String userParentPath = "/user";
private String userPersistent = "/user/persistent";
private String userEphemeral = "/ephemeral";
private String userPersistentSequential = "/user/persistent_sequential";
private String userEphemeralSequential = "/ephemeral_sequential";
private String result = "";
/**
* Curator API 是链式调用风格,遇到 forPath 接口就触发ZooKeeper 调用
*
* 将演示创建 ZooKeeper 四种数据模型
*
* @return
*/
@GetMapping("/create/node")
public String createNode(){
try {
//添加 acl 用户
List<ACL> aclList = new ArrayList<>();
aclList.add(new ACL(ZooDefs.Perms.ALL, new Id(apacheZooKeeperProperties.getScheme(), DigestAuthenticationProvider.generateDigest(apacheZooKeeperProperties.getAuthId()))));
/**
* CuratorListener监听,此监听主要针对background通知和错误通知;
* 使用 watched() 只会观察一次,只对该节点本身 create、delete、setData 有效;
* 使用 inBackground() 会异步监听到返回信息,一旦使用该接口,就不会有返回值
*/
zkClient.getCuratorListenable().addListener(new CuratorListenerImpl());
/**
* NodeCache可以监听节点本身创建、删除,以及内容的变化,但对于子节点的变化不会监听
*/
NodeCache nodeCache = new NodeCache(zkClient,userParentPath);
NodeCacheListenerImpl nodeCacheListener = new NodeCacheListenerImpl();
nodeCacheListener.setNodeCache(nodeCache);
nodeCache.start(true); // 设置为 true 把该节点数据存储到本地
nodeCache.getListenable().addListener(nodeCacheListener);
/**
* PathChildrenCache用于监听所有子节点的变化
*/
PathChildrenCache pathChildrenCache = new PathChildrenCache(zkClient, userParentPath, true);
/**
* StartMode: 初始化方式
* POST_INITIALIZED_EVENT : 异步初始化之后触发事件
* NORMAL:异步初始化
* BUILD_INITIAL_CACHE:同步初始化
*/
pathChildrenCache.start(PathChildrenCache.StartMode.POST_INITIALIZED_EVENT);
pathChildrenCache.getListenable().addListener(new PathChildrenCacheListenerImpl());
// 注册 watch 事件
/*Stat stat = zkClient.checkExists()
.watched()
.forPath(userParentPath);
logger.info("/userParentPath 路径状态..." + stat);
stat = zkClient.checkExists()
.watched()
.forPath(userPersistent);
logger.info("/userPersistent 路径状态..." + stat);
stat = zkClient.checkExists()
.watched()
.forPath(userEphemeral);
logger.info("/userEphemeral 路径状态..." + stat);*/
//持久节点 creatingParentContainersIfNeeded() 接口自动递归创建所需节点的父节点
result = zkClient.create()
.creatingParentContainersIfNeeded()
.withMode(CreateMode.PERSISTENT)
.withACL(aclList)
.forPath(userPersistent, "userPersistentData".getBytes());
Thread.sleep(1000 * 5);
logger.info("持久节点..." + result);
//临时节点 不能有子节点
result = zkClient.create()
.creatingParentContainersIfNeeded()
.withMode(CreateMode.EPHEMERAL)
.forPath(userEphemeral,"userEphemeralData".getBytes());
Thread.sleep(1000 * 5);
logger.info("临时节点..." + result);
//持久序列节点
result = zkClient.create()
.creatingParentContainersIfNeeded()
.withMode(CreateMode.PERSISTENT_SEQUENTIAL)
.forPath(userPersistentSequential,"userPersistentSequentialData".getBytes());
Thread.sleep(1000 * 5);
logger.info("持久有序节点..." + result);
//临时序列节点
result = zkClient.create()
.creatingParentContainersIfNeeded()
.withMode(CreateMode.EPHEMERAL_SEQUENTIAL)
.forPath(userEphemeralSequential,"userEphemeralSequentialData".getBytes());
Thread.sleep(1000 * 5);
logger.info("临时有序节点..." + result);
}catch(Exception e){
logger.info("创建节点失败...");
e.printStackTrace();
}
return "curator api 创建节点";
}
@GetMapping("/node/children")
public String nodeChildren(){
try{
Stat stat = zkClient.checkExists().watched().forPath(userParentPath);
Thread.sleep(1000 * 5);
logger.info("判断节点是否存在..." + stat);
List<String> userPaths = zkClient.getChildren().forPath(userParentPath);
Thread.sleep(1000 * 5);
logger.info("获取所有子节点..." + userPaths);
}catch(Exception e){
logger.info("失败...");
e.printStackTrace();
}
return "curator api 获取所有子节点";
}
@GetMapping("/data/node")
public String dataNode(){
try{
//获取一个节点的内容
byte[] bytes = zkClient.getData().forPath(userPersistent);
Thread.sleep(1000 * 5);
logger.info("获取节点数据..." + new String(bytes));
//修改一个节点的内容
Stat stat = zkClient.setData().forPath(userPersistent, "updateUserPersistentData".getBytes());
Thread.sleep(1000 * 5);
logger.info("修改节点数据..." + stat);
}catch(Exception e){
logger.info("失败...");
e.printStackTrace();
}
return "curator api 获取、修改节点数据";
}
@GetMapping("/delete/node")
public String deleteNode(){
try{
//删除一个节点,强制指定版本进行删除
Stat stat = new Stat();
zkClient.getData().storingStatIn(stat).forPath(userPersistent);
zkClient.delete().withVersion(stat.getVersion()).forPath(userPersistent);
Thread.sleep(1000 * 5);
//删除一个节点,并且递归删除其所有子节点
zkClient.delete().deletingChildrenIfNeeded().forPath(userParentPath);
Thread.sleep(1000 * 5);
}catch(Exception e){
logger.info("删除节点失败...");
e.printStackTrace();
}
return "curator api 删除节点";
}
}
/**
* 连接zooKeeper server,获得zkClient
*/
@Configuration
@EnableConfigurationProperties(value = {ApacheZooKeeperProperties.class, ApacheRetryPolicy.class})
public class ApacheCuratorConfig {
private Logger logger = LoggerFactory.getLogger(ApacheCuratorConfig.class);
@Autowired
private ApacheZooKeeperProperties apacheZooKeeperProperties;
@Autowired
private ApacheRetryPolicy apacheRetryPolicy;
CuratorFramework client = null;
@Bean
public CuratorFramework getCuratorFramework(){
logger.info("zooKeeper client init...");
try {
//当zk连接时失败的重连策略
RetryPolicy retryPolicy = new ExponentialBackoffRetry(apacheRetryPolicy.getBaseSleepTime(), apacheRetryPolicy.getMaxRetries());
//获得实例对象,拿到ZK client
//CuratorFramework client = CuratorFrameworkFactory.newClient(apacheZooKeeperProperties.getConnectUrl(), apacheZooKeeperProperties.getSessionTimeout(), apacheZooKeeperProperties.getConnectionTimeout(), retryPolicy);
List<AuthInfo> authInfos = new ArrayList<>();
authInfos.add(new AuthInfo(apacheZooKeeperProperties.getScheme(), apacheZooKeeperProperties.getAuthId().getBytes()));
client = CuratorFrameworkFactory.builder()
.authorization(authInfos)
.connectString(apacheZooKeeperProperties.getConnectUrl())
.sessionTimeoutMs(apacheZooKeeperProperties.getSessionTimeout())
.connectionTimeoutMs(apacheZooKeeperProperties.getConnectionTimeout())
.retryPolicy(retryPolicy)
.namespace("workspace")
.build();
client.start();
logger.info("zooKeeper client start...");
}catch (Exception e){
logger.info("zooKeeper connect error...");
e.printStackTrace();
}
return client;
}
}