From 517c62f1a82b2def5c0ebaa5b0d4bb29f163f185 Mon Sep 17 00:00:00 2001 From: zhouyu <3065526146@qq.com> Date: Tue, 17 Dec 2024 08:15:07 +0800 Subject: [PATCH] 111 --- .../swg/keygen/SnowFlakeKeyGenerator.java | 36 +++++++++++++++++-- 1 file changed, 34 insertions(+), 2 deletions(-) diff --git a/snailmall-keygen-service/src/main/java/com/njupt/swg/keygen/SnowFlakeKeyGenerator.java b/snailmall-keygen-service/src/main/java/com/njupt/swg/keygen/SnowFlakeKeyGenerator.java index 9f75fb2..19053bb 100644 --- a/snailmall-keygen-service/src/main/java/com/njupt/swg/keygen/SnowFlakeKeyGenerator.java +++ b/snailmall-keygen-service/src/main/java/com/njupt/swg/keygen/SnowFlakeKeyGenerator.java @@ -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 >= 0L && 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);