实现原理
zookeeper操作path数据时,version会增量+1,这个version可以当作分布式id使用。
注意:
1.path必须为持久节点
- 本文基于springboot示例
具体实现
- 引入依赖
ps: Zookeeper原生API比较复杂度。Curator帮助我们在其基础上进行封装、实现一些开发细节、Fluent的编程风格。目前为Apache的顶级项目,是最流行的Zookeeper客户端之一。
<!-- https://mvnrepository.com/artifact/org.apache.zookeeper/zookeeper -->
<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
<version>3.6.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.curator/curator-framework -->
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-framework</artifactId>
<version>5.0.0</version>
</dependency>
- zookeeper config
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.retry.RetryForever;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class ZookeeperConfig {
@Bean
public CuratorFramework curatorFramework(){
CuratorFramework cf = CuratorFrameworkFactory.builder()
.connectString("192.168.0.xxx:2181,192.168.0.xxx:2182,192.168.0.xxx:2183")
.sessionTimeoutMs(60000)
.connectionTimeoutMs(2000)
.retryPolicy(new RetryForever(2000))
.namespace("test")
.build();
cf.start();
return cf;
}}
- 具体实现类
import com.dang.util.SpringContextUtil;
import org.apache.curator.framework.CuratorFramework;
import org.apache.zookeeper.data.Stat;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
/**
* zookeeper 获取递增id
*/
public class ZkIncrementId {
CuratorFramework curatorFramework = SpringContextUtil.getBean(CuratorFramework.class);
private final byte[] emptyValue = new byte[0];
private String basePath = "/incrementId";
private String extPath = null;
private LocalDate date = null;
private final DateTimeFormatter df = DateTimeFormatter.ofPattern("yyyy-MM-dd");
/**
* 构造函数
* @param basePath 根目录
*/
public ZkIncrementId(String basePath){
this.extPath = extPath;
init();
}
/**
* 构造函数
* @param basePath 根目录
* @param date 按日期生成
*/
public ZkIncrementId(String basePath,LocalDate date){
this.extPath = basePath;
this.date = date;
init();
}
public int next(){
String path = getPath();
try {
return curatorFramework.setData().forPath(path,emptyValue).getVersion();
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
private void init(){
String path = getPath();
try {
if (curatorFramework.checkExists().forPath(path)==null){
//Stat stat = new Stat();
curatorFramework.create()
.creatingParentsIfNeeded()
// .storingStatIn(stat)
.forPath(path,emptyValue);
}
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
private String getPath(){
return basePath
.concat(this.extPath==null?""
:extPath.indexOf("/")==0?extPath
:("/"+extPath))
.concat(this.date==null?"":
("/"+df.format(this.date)));
}
}
- spring获取bean辅助类
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
@Component
public class SpringContextUtil implements ApplicationContextAware {
private static ApplicationContext context;
@Override
public void setApplicationContext(ApplicationContext contex) throws BeansException {
System.out.println("--------------------SpringContextUtil--------------------");
context = contex;
}
public static ApplicationContext getApplicationContext() {
return context;
}
public static <T> T getBean(Class<T> clazz) {
return context.getBean(clazz);
}
public static <T> T getBean(String beanName) {
return (T) context.getBean(beanName);
}
public static String getActiveProfile() {
return context.getEnvironment().getActiveProfiles()[0];
}
}
调用示例
//path defaultId 下自增长id
ZkIncrementId zkIncrementId1 = new ZkIncrementId("defaultId");
zkIncrementId1.next();
//path orderid 下,按天,自增长id
ZkIncrementId zkIncrementId2 = new ZkIncrementId("orderid",LocalDate.now());
zkIncrementId2.next();