@ -17,38 +17,62 @@ import com.google.common.base.Preconditions;
* @CONTACT 317758022 @qq.com
* @DESC
* /
// 使用了lombok的@Slf4j注解, 用于自动生成日志相关的代码, 方便在类中进行日志记录
@Slf4j
// 将该类标记为Spring的服务组件, 名称为"snowFlakeKeyGenerator", 方便在Spring容器中进行依赖注入和管理
@Service ( "snowFlakeKeyGenerator" )
public class SnowFlakeKeyGenerator implements KeyGenerator {
public class SnowFlakeKeyGenerator implements KeyGenerator {
// 通过Spring的依赖注入机制, 自动注入WorkerIDSenquence类型的实例, 用于获取相关序列信息
@Autowired
private WorkerIDSenquence workerIDSenquence ;
// 定义时间戳起始时间( 纪元时间) , 后续生成唯一ID时会基于此时间进行计算, 初始值在静态代码块中赋值
public static final long EPOCH ;
// 用于表示序列号占用的位数, 这里定义为12位
private static final long SEQUENCE_BITS = 12L ;
// 用于表示工作机器ID占用的位数, 这里定义为10位
private static final long WORKER_ID_BITS = 10L ;
// 序列号的掩码, 用于在对序列号进行操作时进行位运算的限制, 通过计算得到的值( 2的12次方 - 1)
private static final long SEQUENCE_MASK = 4095L ;
// 工作机器ID左移的位数, 用于在生成唯一ID时将工作机器ID放置到合适的二进制位位置
private static final long WORKER_ID_LEFT_SHIFT_BITS = 12L ;
// 时间戳左移的位数, 用于在生成唯一ID时将时间戳放置到合适的二进制位位置
private static final long TIMESTAMP_LEFT_SHIFT_BITS = 22L ;
// 工作机器ID的最大值, 通过计算得到( 2的10次方) , 用于限制工作机器ID的取值范围
private static final long WORKER_ID_MAX_VALUE = 1024L ;
// 定义一个时间服务类的实例, 用于获取当前时间等时间相关操作, 初始化为默认的TimeService实例
private static TimeService timeService = new TimeService ( ) ;
// 记录当前工作机器的ID, 初始值在初始化方法中赋值
private static long workerId ;
// 当前的序列号, 用于在同一时间戳内区分不同的生成请求, 每次生成新ID时会进行相应变化
private long sequence ;
// 记录上一次生成ID时的时间戳, 用于对比当前时间戳, 判断是否需要更新序列号等操作
private long lastTime ;
// 默认构造函数
public SnowFlakeKeyGenerator ( ) {
}
/ * *
* 初 始 化 workerID 从 ZK 获 取 序 列
* 初 始 化 workerID , 通 过 调 用 workerIDSenquence 的 方 法 从 ZK ( 可 能 是 Zookeeper ) 获 取 序 列
* 同 时 会 进 行 参 数 校 验 , 确 保 获 取 到 的 workerID 在 合 法 的 取 值 范 围 内 ( 0 到 1024 之 间 )
* /
@PostConstruct
public void initWorkerId ( ) throws Exception {
long workerID = workerIDSenquence . getSequence ( null ) ;
// 使用Preconditions进行前置条件校验, 确保workerID合法
Preconditions . checkArgument ( workerID > = 0 L & & workerID < 1024L ) ;
workerId = workerID ;
}
/ * *
* 生 成 唯 一 ID 的 核 心 方 法 , 遵 循 雪 花 算 法 的 基 本 逻 辑
* 首 先 获 取 当 前 时 间 戳 , 然 后 检 查 时 间 是 否 正 常 ( 防 止 时 间 倒 退 情 况 )
* 如 果 当 前 时 间 戳 和 上 一 次 时 间 戳 相 同 , 则 对 序 列 号 进 行 递 增 处 理 , 若 序 列 号 达 到 最 大 值 则 等 待 下 一 个 时 间 周 期
* 如 果 时 间 戳 不 同 , 则 重 置 序 列 号 为 0
* 最 后 根 据 时 间 戳 、 工 作 机 器 ID 和 序 列 号 组 装 生 成 唯 一 的 长 整 型 ID , 并 返 回
* /
public synchronized Number generateKey ( ) {
long currentMillis = timeService . getCurrentMillis ( ) ;
Preconditions . checkState ( this . lastTime < = currentMillis , "Clock is moving backwards, last time is %d milliseconds, current time is %d milliseconds" , new Object [ ] { Long . valueOf ( this . lastTime ) , Long . valueOf ( currentMillis ) } ) ;
@ -68,6 +92,10 @@ public class SnowFlakeKeyGenerator implements KeyGenerator{
return Long . valueOf ( currentMillis - EPOCH < < 22 | workerId < < 12 | this . sequence ) ;
}
/ * *
* 当 序 列 号 达 到 最 大 值 时 , 等 待 直 到 进 入 下 一 个 时 间 周 期 ( 即 获 取 到 大 于 当 前 时 间 戳 的 时 间 )
* 通 过 循 环 不 断 获 取 当 前 时 间 , 直 到 时 间 大 于 传 入 的 上 一 次 时 间 戳
* /
private long waitUntilNextTime ( long lastTime ) {
long time ;
for ( time = timeService . getCurrentMillis ( ) ; time < = lastTime ; time = timeService . getCurrentMillis ( ) ) {
@ -77,10 +105,14 @@ public class SnowFlakeKeyGenerator implements KeyGenerator{
return time ;
}
/ * *
* 设 置 时 间 服 务 类 的 实 例 , 用 于 替 换 默 认 的 时 间 服 务 实 现 , 方 便 进 行 时 间 相 关 功 能 的 定 制 或 替 换
* /
public static void setTimeService ( TimeService timeService ) {
timeService = timeService ;
}
// 静态代码块, 用于初始化EPOCH( 纪元时间) , 将时间设置为2016年11月1日0时0分0秒0毫秒
static {
Calendar calendar = Calendar . getInstance ( ) ;
calendar . set ( 2016 , 10 , 1 ) ;