<dependency>
<groupId>org.apache.curatorgroupId>
<artifactId>curator-recipesartifactId>
<version>4.2.0version>
dependency>
<dependency>
<groupId>org.apache.curatorgroupId>
<artifactId>curator-frameworkartifactId>
<version>4.2.0version>
dependency>
添加配置文件
# zk host地址
zk.host=note01:2181,note02:2181,note03:2181
# zk自增存储node
zk.sequence-path=/leadnews/sequence/
定义枚举类,枚举表名
public enum ZkSequenceEnum {
AP_LIKES,AP_READ_BEHAVIOR,AP_COLLECTION,AP_USER_FOLLOW,AP_USER_FAN
}
分布式原子自增类(DistributedAtomicLong)实现,注意每500毫秒重试3次后仍然生成失败则返回null,
import org.apache.curator.RetryPolicy;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.recipes.atomic.AtomicValue;
import org.apache.curator.framework.recipes.atomic.DistributedAtomicLong;
import org.apache.curator.retry.ExponentialBackoffRetry;
public class ZkSequence {
//
RetryPolicy retryPolicy = new ExponentialBackoffRetry(500,3);
DistributedAtomicLong distAtomicLong;
public ZkSequence(CuratorFramework client, String counterPath){
this.distAtomicLong = distAtomicLong = new DistributedAtomicLong(client,counterPath,retryPolicy);
}
/**
* 生成序列
* @return
* @throws Exception
*/
public Long sequence() throws Exception {
AtomicValue<Long> increment = distAtomicLong.increment();
if(increment.succeeded()){
return increment.postValue();
}else{
return null;
}
}
}
构建zookeeper client,通过PostConstruct注解在内构器之后调用init方法初始化客户端连接,并调用initZkSequence方法初始项目所定义的ZkSequence,并存储在zkSequence的Map集合中,最终提供sequence方法来查询对应zkSequence获取自增ID
被@PostConstruct修饰的方法会在服务器加载Servlet的时候运行,并且只会被服务器调用一次,类似于Serclet的inti()方法。被@PostConstruct修饰的方法会在构造函数之后,init()方法之前运行。
package com.heima.common.zookeeper;
import com.google.common.collect.Maps;
import com.heima.common.zookeeper.sequence.ZkSequence;
import com.heima.common.zookeeper.sequence.ZkSequenceEnum;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.retry.ExponentialBackoffRetry;
import javax.annotation.PostConstruct;
import java.util.Map;
@Getter
@Setter
@Slf4j
public class ZookeeperClient {
private String host;
private String sequencePath;
// 重试休眠时间
private final int SLEEP_TIME_MS = 1000;
// 最大重试1000次
private final int MAX_RETRIES = 1000;
//会话超时时间
private final int SESSION_TIMEOUT = 30 * 1000;
//连接超时时间
private final int CONNECTION_TIMEOUT = 3 * 1000;
//创建连接实例
private CuratorFramework client = null;
// 序列化集合
private Map<String, ZkSequence> zkSequence = Maps.newConcurrentMap();
public ZookeeperClient(String host, String sequencePath) {
this.host = host;
this.sequencePath = sequencePath;
}
@PostConstruct
public void init() throws Exception {
CuratorFrameworkFactory.builder()
.connectString(this.getHost())
.connectionTimeoutMs(CONNECTION_TIMEOUT)
.sessionTimeoutMs(SESSION_TIMEOUT)
.retryPolicy(new ExponentialBackoffRetry(SLEEP_TIME_MS, MAX_RETRIES)).build();
this.client.start();
this.initZkSequence();
}
private void initZkSequence() {
ZkSequenceEnum[] list = ZkSequenceEnum.values();
for (int i = 0; i < list.length; i++) {
String name = list[i].name();
String path = this.sequencePath + name;
ZkSequence zep = new ZkSequence(this.client, path);
zkSequence.put(name,zep);
}
}
public Long sequence(ZkSequenceEnum name){
try{
ZkSequence seq = zkSequence.get(name.name());
if (seq != null){
return seq.sequence();
}
}catch (Exception e){
log.error("获取[{}]Sequence错误:{}",name,e);
}
return null;
}
}
配置管理
import lombok.Getter;
import lombok.Setter;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
@Setter
@Getter
@Configuration
@ConfigurationProperties(prefix="zk")
@PropertySource("classpath:zookeeper.properties")
public class ZkConfig {
String host;
String sequencePath;
@Bean
public ZookeeperClient zookeeperClient(){
return new ZookeeperClient(this.host,this.sequencePath);
}
}
为便于程序中调用,以及对自增生成失败的统一处理,暴露生成自增主键的功能
@Component
public class Sequences {
@Autowired
private ZookeeperClient client;
public Long sequenceApLikes(){
return this.client.sequence(ZkSequenceEnum.AP_LIKES);
}
public Long sequenceApReadBehavior(){
return this.client.sequence(ZkSequenceEnum.AP_READ_BEHAVIOR);
}
public Long sequenceApCollection(){
return this.client.sequence(ZkSequenceEnum.AP_COLLECTION);
}
public Long sequenceApUserFollow(){return this.client.sequence(ZkSequenceEnum.AP_USER_FOLLOW);}
public Long sequenceApUserFan(){return this.client.sequence(ZkSequenceEnum.AP_USER_FAN);}
}
使用
// 第一步,注入Sequences
@Autowired
private Sequences sequences;
// 第二步,在方法中调用生成
alb.setId(sequences.sequenceApCollection());