فهرست منبع

Merge remote-tracking branch 'origin/master'

zhou-hao 7 سال پیش
والد
کامیت
0ab2ae7eea

+ 19 - 0
hsweb-core/src/main/java/org/hswebframework/web/id/IDGenerator.java

@@ -33,10 +33,19 @@ import java.security.NoSuchAlgorithmException;
 public interface IDGenerator<T> {
     T generate();
 
+    /**
+     * 使用UUID生成id
+     */
     IDGenerator<String> UUID = java.util.UUID.randomUUID()::toString;
 
+    /**
+     * 随机字符
+     */
     IDGenerator<String> RANDOM = RandomUtil::randomChar;
 
+    /**
+     * md5(uuid()+random())
+     */
     IDGenerator<String> MD5 = () -> {
         try {
             MessageDigest md = MessageDigest.getInstance("MD5");
@@ -46,4 +55,14 @@ public interface IDGenerator<T> {
             throw new RuntimeException(e);
         }
     };
+
+    /**
+     * 雪花算法
+     */
+    IDGenerator<Long> SNOW_FLAKE = SnowflakeIdGenerator.getInstance()::nextId;
+
+    /**
+     * 雪花算法的16进制
+     */
+    IDGenerator<String> SNOW_FLAKE_HEX = () -> Long.toHexString(SNOW_FLAKE.generate());
 }

+ 91 - 0
hsweb-core/src/main/java/org/hswebframework/web/id/SnowflakeIdGenerator.java

@@ -0,0 +1,91 @@
+package org.hswebframework.web.id;
+
+import lombok.extern.slf4j.Slf4j;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.*;
+
+@Slf4j
+public class SnowflakeIdGenerator {
+
+    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 static final SnowflakeIdGenerator generator;
+
+    static {
+        Random random = new Random();
+        long workerId = Long.getLong("id-worker", random.nextInt(31));
+        long dataCenterId = Long.getLong("id-datacenter", random.nextInt(31));
+        generator = new SnowflakeIdGenerator(workerId, dataCenterId);
+    }
+
+    public static SnowflakeIdGenerator getInstance() {
+        return generator;
+    }
+
+    public SnowflakeIdGenerator(long workerId, long dataCenterId) {
+        // 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;
+        log.info("worker starting. timestamp left shift {}, datacenter id bits {}, worker id bits {}, sequence bits {}, workerid {}", timestampLeftShift, datacenterIdBits, workerIdBits, sequenceBits, workerId);
+    }
+
+    public synchronized long nextId() {
+        long timestamp = timeGen();
+
+        if (timestamp < lastTimestamp) {
+            log.error("clock is moving backwards.  Rejecting requests until {}.", lastTimestamp);
+            throw new UnsupportedOperationException(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 timeGen() {
+        return System.currentTimeMillis();
+    }
+
+}

+ 27 - 0
hsweb-core/src/test/java/org/hswebframework/web/id/IDGeneratorTests.java

@@ -0,0 +1,27 @@
+package org.hswebframework.web.id;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+/**
+ * @author zhouhao
+ * @since 3.0
+ */
+public class IDGeneratorTests {
+
+    @Test
+    public void test() {
+        System.setProperty("id-worker","1");
+        System.setProperty("id-datacenter","1");
+
+        Assert.assertNotNull(IDGenerator.UUID.generate());
+        Assert.assertNotNull(IDGenerator.MD5.generate());
+        Assert.assertNotNull(IDGenerator.RANDOM.generate());
+        Assert.assertNotNull(IDGenerator.SNOW_FLAKE.generate());
+        Assert.assertNotNull(IDGenerator.SNOW_FLAKE_HEX.generate());
+
+        for (int i = 0; i < 100; i++) {
+            System.out.println(IDGenerator.SNOW_FLAKE.generate());
+        }
+    }
+}