Looly 5 years ago
parent
commit
7cd260c1ea
2 changed files with 58 additions and 52 deletions
  1. 1 0
      CHANGELOG.md
  2. 57 52
      hutool-core/src/main/java/cn/hutool/core/lang/Snowflake.java

+ 1 - 0
CHANGELOG.md

@@ -8,6 +8,7 @@
 ### 新特性
 * 【core 】     废弃isMactchRegex,改为isMatchRegex(方法错别字)
 * 【core 】     修正hasNull()方法上注释错误(issue#I18TAG@Gitee)
+* 【core 】     Snowflake的起始时间可以被指定(pr#95@Gitee)
 ### Bug修复
 * 【core 】     CharsetUtil在不支持GBK的系统中运行报错问题(issue#731@Github)
 * 【core 】     RandomUtil的randomEleSet方法顺序不随机的问题(pr#741@Github)

+ 57 - 52
hutool-core/src/main/java/cn/hutool/core/lang/Snowflake.java

@@ -1,104 +1,108 @@
 package cn.hutool.core.lang;
 
-import java.io.Serializable;
-import java.util.Date;
-
-import cn.hutool.core.date.DateUtil;
 import cn.hutool.core.date.SystemClock;
 import cn.hutool.core.util.StrUtil;
 
+import java.io.Serializable;
+import java.util.Date;
+
 /**
  * Twitter的Snowflake 算法<br>
  * 分布式系统中,有一些需要使用全局唯一ID的场景,有些时候我们希望能使用一种简单一些的ID,并且希望ID能够按照时间有序生成。
- * 
+ *
  * <p>
  * snowflake的结构如下(每部分用-分开):<br>
- * 
+ *
  * <pre>
  * 0 - 0000000000 0000000000 0000000000 0000000000 0 - 00000 - 00000 - 000000000000
  * </pre>
- * 
+ * <p>
  * 第一位为未使用(符号位表示正数),接下来的41位为毫秒级时间(41位的长度可以使用69年)<br>
  * 然后是5位datacenterId和5位workerId(10位的长度最多支持部署1024个节点)<br>
  * 最后12位是毫秒内的计数(12位的计数顺序号支持每个节点每毫秒产生4096个ID序号)
- * 
+ * <p>
  * 并且可以通过生成的id反推出生成时间,datacenterId和workerId
  * <p>
  * 参考:http://www.cnblogs.com/relucent/p/4955340.html
- * 
+ *
  * @author Looly
  * @since 3.0.1
  */
-public class Snowflake implements Serializable{
+public class Snowflake implements Serializable {
 	private static final long serialVersionUID = 1L;
 
-	// Thu, 04 Nov 2010 01:42:54 GMT
-	private long twepoch = 1288834974657L;
+	private final long twepoch;
 	private final long workerIdBits = 5L;
-	private final long datacenterIdBits = 5L;
+	private final long dataCenterIdBits = 5L;
 	//// 最大支持机器节点数0~31,一共32个
-	private final long maxWorkerId = -1L ^ (-1L << workerIdBits);
 	// 最大支持数据中心节点数0~31,一共32个
-	private final long maxDatacenterId = -1L ^ (-1L << datacenterIdBits);
+	@SuppressWarnings({"PointlessBitwiseExpression", "FieldCanBeLocal"})
+	private final long maxWorkerId = -1L ^ (-1L << workerIdBits);
+	@SuppressWarnings({"PointlessBitwiseExpression", "FieldCanBeLocal"})
+	private final long maxDataCenterId = -1L ^ (-1L << dataCenterIdBits);
 	// 序列号12位
 	private final long sequenceBits = 12L;
 	// 机器节点左移12位
 	private final long workerIdShift = sequenceBits;
 	// 数据中心节点左移17位
-	private final long datacenterIdShift = sequenceBits + workerIdBits;
+	private final long dataCenterIdShift = sequenceBits + workerIdBits;
 	// 时间毫秒数左移22位
-	private final long timestampLeftShift = sequenceBits + workerIdBits + datacenterIdBits;
+	private final long timestampLeftShift = sequenceBits + workerIdBits + dataCenterIdBits;
+	@SuppressWarnings({"PointlessBitwiseExpression", "FieldCanBeLocal"})
 	private final long sequenceMask = -1L ^ (-1L << sequenceBits);// 4095
 
 	private long workerId;
-	private long datacenterId;
+	private long dataCenterId;
 	private long sequence = 0L;
 	private long lastTimestamp = -1L;
 	private boolean useSystemClock;
 
 	/**
 	 * 构造
-	 * 
-	 * @param workerId 终端ID
-	 * @param datacenterId 数据中心ID
+	 *
+	 * @param workerId     终端ID
+	 * @param dataCenterId 数据中心ID
 	 */
-	public Snowflake(long workerId, long datacenterId) {
-		this(workerId, datacenterId, false);
+	public Snowflake(long workerId, long dataCenterId) {
+		this(workerId, dataCenterId, false);
 	}
 
 	/**
 	 * 构造
-	 * 
-	 * @param workerId 终端ID
-	 * @param datacenterId 数据中心ID
+	 *
+	 * @param workerId         终端ID
+	 * @param dataCenterId     数据中心ID
 	 * @param isUseSystemClock 是否使用{@link SystemClock} 获取当前时间戳
 	 */
-	public Snowflake(long workerId, long datacenterId, boolean isUseSystemClock) {
+	public Snowflake(long workerId, long dataCenterId, boolean isUseSystemClock) {
+		this(null, workerId, dataCenterId, isUseSystemClock);
+	}
+
+	/**
+	 * @param epochDate        初始化时间起点(null表示默认起始日期),后期修改会导致id重复,如果要修改连workerId dataCenterId,慎用
+	 * @param workerId         工作机器节点id
+	 * @param dataCenterId     数据中心id
+	 * @param isUseSystemClock 是否使用{@link SystemClock} 获取当前时间戳
+	 * @since 5.1.3
+	 */
+	public Snowflake(Date epochDate, long workerId, long dataCenterId, boolean isUseSystemClock) {
+		if (null != epochDate) {
+			this.twepoch = epochDate.getTime();
+		} else{
+			// Thu, 04 Nov 2010 01:42:54 GMT
+			this.twepoch = 1288834974657L;
+		}
 		if (workerId > maxWorkerId || workerId < 0) {
 			throw new IllegalArgumentException(StrUtil.format("worker Id can't be greater than {} or less than 0", maxWorkerId));
 		}
-		if (datacenterId > maxDatacenterId || datacenterId < 0) {
-			throw new IllegalArgumentException(StrUtil.format("datacenter Id can't be greater than {} or less than 0", maxDatacenterId));
+		if (dataCenterId > maxDataCenterId || dataCenterId < 0) {
+			throw new IllegalArgumentException(StrUtil.format("datacenter Id can't be greater than {} or less than 0", maxDataCenterId));
 		}
 		this.workerId = workerId;
-		this.datacenterId = datacenterId;
+		this.dataCenterId = dataCenterId;
 		this.useSystemClock = isUseSystemClock;
 	}
-	/**
-	 * 
-	 * @param epochStr 初始化时间起点 后期修改会导致id重复,如果要修改连workerId datacenterId 一起修改 慎用,格式yyyyMMdd,
-	 * @param workerId 工作机器节点id
-	 * @param datacenterId 数据中心id
-	 * @param isUseSystemClock 是否使用{@link SystemClock} 获取当前时间戳
-	 */
-	public Snowflake(String epochStr, long workerId, long datacenterId, boolean isUseSystemClock) {
-		this(workerId, datacenterId, isUseSystemClock);
-		Date d=DateUtil.parse(epochStr, "yyyyMMdd");
-		long twepoch=d.getTime();
-		if(twepoch>this.twepoch){
-			this.twepoch=twepoch;
-		}
-	}
+
 	/**
 	 * 根据Snowflake的ID,获取机器id
 	 *
@@ -116,11 +120,11 @@ public class Snowflake implements Serializable{
 	 * @return 所属数据中心
 	 */
 	public long getDataCenterId(long id) {
-		return id >> datacenterIdShift & ~(-1L << datacenterIdBits);
+		return id >> dataCenterIdShift & ~(-1L << dataCenterIdBits);
 	}
 
 	/**
-	 *根据Snowflake的ID,获取生成时间
+	 * 根据Snowflake的ID,获取生成时间
 	 *
 	 * @param id snowflake算法生成的id
 	 * @return 生成的时间
@@ -131,7 +135,7 @@ public class Snowflake implements Serializable{
 
 	/**
 	 * 下一个ID
-	 * 
+	 *
 	 * @return ID
 	 */
 	public synchronized long nextId() {
@@ -151,9 +155,9 @@ public class Snowflake implements Serializable{
 
 		lastTimestamp = timestamp;
 
-		return ((timestamp - twepoch) << timestampLeftShift) | (datacenterId << datacenterIdShift) | (workerId << workerIdShift) | sequence;
+		return ((timestamp - twepoch) << timestampLeftShift) | (dataCenterId << dataCenterIdShift) | (workerId << workerIdShift) | sequence;
 	}
-	
+
 	/**
 	 * 下一个ID(字符串形式)
 	 *
@@ -164,9 +168,10 @@ public class Snowflake implements Serializable{
 	}
 
 	// ------------------------------------------------------------------------------------------------------------------------------------ Private method start
+
 	/**
 	 * 循环等待下一个时间
-	 * 
+	 *
 	 * @param lastTimestamp 上次记录的时间
 	 * @return 下一个时间
 	 */
@@ -180,7 +185,7 @@ public class Snowflake implements Serializable{
 
 	/**
 	 * 生成时间戳
-	 * 
+	 *
 	 * @return 时间戳
 	 */
 	private long genTime() {