1.引入依赖(主要是zookeeper的3.5.8的依赖)
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>cn.tuling</groupId>
<artifactId>apache-curator</artifactId>
<version>1.0-SNAPSHOT</version>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
</build>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-recipes</artifactId>
<version>5.0.0</version>
<exclusions>
<exclusion>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-x-discovery</artifactId>
<version>5.0.0</version>
<exclusions>
<exclusion>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
<version>3.5.8</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.12</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.8.3</version>
</dependency>
</dependencies>
</project>
2.创建ConfigCenter类
注意点:这一行实现了循环监听的功能,主要在于这个this
注意点:
这是一种同步的创建节点的方式:
package zookeeper.client;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.zookeeper.*;
import java.io.IOException;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
@Slf4j
public class ConfigCenter {
private final static String CONNECT_STR="192.168.109.200:2181";
private final static Integer SESSION_TIMEOUT=30*1000;
private static ZooKeeper zooKeeper=null;
private static CountDownLatch countDownLatch=new CountDownLatch(1);
public static void main(String[] args) throws IOException, InterruptedException, KeeperException {
zooKeeper=new ZooKeeper(CONNECT_STR, SESSION_TIMEOUT, new Watcher() {
@Override
public void process(WatchedEvent event) {
if (event.getType()== Event.EventType.None
&& event.getState() == Event.KeeperState.SyncConnected){
log.info("连接已建立");
countDownLatch.countDown();
}
}
});
countDownLatch.await();
MyConfig myConfig = new MyConfig();
myConfig.setKey("anykey");
myConfig.setName("anyName");
ObjectMapper objectMapper=new ObjectMapper();
byte[] bytes = objectMapper.writeValueAsBytes(myConfig);
String s = zooKeeper.create("/myconfig", bytes, ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
Watcher watcher = new Watcher() {
@SneakyThrows
@Override
public void process(WatchedEvent event) {
if (event.getType()== Event.EventType.NodeDataChanged
&& event.getPath()!=null && event.getPath().equals("/myconfig")){
log.info(" PATH:{} 发生了数据变化" ,event.getPath());
byte[] data = zooKeeper.getData("/myconfig", this, null);
MyConfig newConfig = objectMapper.readValue(new String(data), MyConfig.class);
log.info("数据发生变化: {}",newConfig);
}
}
};
byte[] data = zooKeeper.getData("/myconfig", watcher, null);
MyConfig originalMyConfig = objectMapper.readValue(new String(data), MyConfig.class);
log.info("原始数据: {}", originalMyConfig);
TimeUnit.SECONDS.sleep(Integer.MAX_VALUE);
}
}
3.实体类
package zookeeper.client; import lombok.Data; import lombok.NoArgsConstructor; import lombok.ToString; @Data @ToString @NoArgsConstructor public class MyConfig { private String key; private String name; }
启动后,就可以在zookeeper服务端看到已经创建了这个节点,而且在服务端修改后,也能在java代码客户端控制台看到动态感知变化的日志打印:
补充源码部分:
new Zookeeper其实是异步的一个过程,开启了两个守护线程。守护线程特点:当业务线程没有在运行的时候,守护线程会自动退出。 在上面那个例子中,main线程就是一个业务线程。所以,上面的代码中有这么一段:
ClientCnxn是一个管理连接的类
sendThread 是客户端往服务端发送数据的一个线程
evnetThread是接收服务端响应的一个线程
点开这个sendThread,他其实是一个守护线程