该类作为分布式中 id生成的工具类,为保证所有节点生成的id都是唯一的,使用redis作为缓存
所以在
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.redis.core.RedisTemplate;
//@Component
public class IdWorker {
protected static final Logger LOG = LoggerFactory.getLogger(IdWorker.class);
private long workerId;
private long datacenterId;
private long sequence = 0L;
private long twepoch = 1288834974657L;
private long workerIdBits = 5L;
private long datacenterIdBits = 5L;
private long maxWorkerId = -1L ^ (-1L << workerIdBits);
private long maxDatacenterId = -1L ^ (-1L << datacenterIdBits);
private long sequenceBits = 12L;
private long workerIdShift = sequenceBits;
private long datacenterIdShift = sequenceBits + workerIdBits;
private long timestampLeftShift = sequenceBits + workerIdBits + datacenterIdBits;
private long sequenceMask = -1L ^ (-1L << sequenceBits);
private long lastTimestamp = -1L;
private long batchLastTimestamp = -1L;
private long batchSequence = 0L;
private RedisTemplate redisTemplate;
private static final String ID_KEY = "id_key";
public static final Integer ONE_INTEGER = 1;
public static Integer ID_BATCH_MAX=500;
public static final Integer ZERO_INTEGER = 0;
public static final Long ZERO_LONG = 0L;
private Long lastBatchEndId = -1L;
private Long lastId = -1L;
public IdWorker(long workerId, long datacenterId, RedisTemplate redisTemplate) {
// sanity check for workerId
if (workerId > maxWorkerId || workerId < 0) {
throw new IllegalArgumentException(String.format("worker Id can't be greater than %d or less than 0", maxWorkerId));
}
if (datacenterId > maxDatacenterId || datacenterId < 0) {
throw new IllegalArgumentException(String.format("datacenter Id can't be greater than %d or less than 0", maxDatacenterId));
}
this.workerId = workerId;
this.datacenterId = datacenterId;
this.redisTemplate = redisTemplate;
LOG.info(String.format("worker starting. timestamp left shift %d, datacenter id bits %d, worker id bits %d, sequence bits %d, workerid %d", timestampLeftShift, datacenterIdBits, workerIdBits, sequenceBits, workerId));
}
public synchronized long nextId() {
long timestamp = timeGen();
if (timestamp < lastTimestamp) {
LOG.error(String.format("clock is moving backwards. Rejecting requests until %d.", lastTimestamp));
throw new RuntimeException(String.format("Clock moved backwards. Refusing to generate id for %d milliseconds", lastTimestamp - timestamp));
}
if (lastTimestamp == timestamp) {
sequence = (sequence + 1) & sequenceMask;
if (sequence == 0) {
timestamp = tilNextMillis(lastTimestamp);
}
} else {
sequence = 0L;
}
lastTimestamp = timestamp;
return ((timestamp - twepoch) << timestampLeftShift) //时间戳部分
| (datacenterId << datacenterIdShift) //数据中心部分
| (workerId << workerIdShift) //机器标识部分
| sequence; //序列号部分
}
protected long tilNextMillis(long lastTimestamp) {
long timestamp = timeGen();
while (timestamp <= lastTimestamp) {
timestamp = timeGen();
}
return timestamp;
}
protected long batchTilNextMillis(long lastTimestamp) {
long timestamp = batchTimeGen();
while (timestamp <= lastTimestamp) {
timestamp = batchTimeGen();
}
return timestamp;
}
protected long timeGen() {
return redisTemplate.opsForValue().increment(ID_KEY, 0);
}
/**
* 批量获取id:一次取500,未到终点id,则返回上一次id + 1,否则重新批量获取,主要用于批量业务
* @return
*/
protected long batchTimeGen() {
if (lastId < lastBatchEndId) {
lastId = lastId + ONE_INTEGER;
return lastId;
} else {
lastBatchEndId = redisTemplate.opsForValue().increment(ID_KEY, ID_BATCH_MAX);
lastId = lastBatchEndId - ID_BATCH_MAX + ONE_INTEGER;
return lastId;
}
}
/**
* 获取批量id
* @return
*/
public synchronized long batchNextId() {
long timestamp = batchTimeGen();
if (timestamp < batchLastTimestamp) {
LOG.error(String.format("clock is moving backwards. Rejecting requests until %d.", batchLastTimestamp));
throw new RuntimeException(String.format("Clock moved backwards. Refusing to generate id for %d milliseconds", batchLastTimestamp - timestamp));
}
if (batchLastTimestamp == timestamp) {
batchSequence = (batchSequence + ONE_INTEGER) & sequenceMask;
if (batchSequence == ZERO_INTEGER) {
timestamp = batchTilNextMillis(batchLastTimestamp);
}
} else {
batchSequence = ZERO_LONG;
}
batchLastTimestamp = timestamp;
return ((timestamp - twepoch) << timestampLeftShift) | (datacenterId << datacenterIdShift) | (workerId << workerIdShift) | batchSequence;
}
}