From 63fe0e8824dc51c7d6e9e35164643bfdbd42ad6e Mon Sep 17 00:00:00 2001 From: sxu <602087911@qq.com> Date: Mon, 27 Jan 2025 12:11:19 +0800 Subject: [PATCH] id --- .../main/java/net/xnzn/framework/id/Id.java | 53 ++++++ .../net/xnzn/framework/id/IdProperties.java | 107 +++++++++++ .../framework/id/IdWorkAutoConfiguration.java | 169 ++++++++++++++++++ 3 files changed, 329 insertions(+) create mode 100644 bonus-common-biz/Id/src/main/java/net/xnzn/framework/id/Id.java create mode 100644 bonus-common-biz/Id/src/main/java/net/xnzn/framework/id/IdProperties.java create mode 100644 bonus-common-biz/Id/src/main/java/net/xnzn/framework/id/IdWorkAutoConfiguration.java diff --git a/bonus-common-biz/Id/src/main/java/net/xnzn/framework/id/Id.java b/bonus-common-biz/Id/src/main/java/net/xnzn/framework/id/Id.java new file mode 100644 index 0000000..7f539be --- /dev/null +++ b/bonus-common-biz/Id/src/main/java/net/xnzn/framework/id/Id.java @@ -0,0 +1,53 @@ +package net.xnzn.framework.id; + +import com.google.common.base.Preconditions; +import java.time.LocalDateTime; +import java.time.ZoneId; + +public class Id { + private static final long EPOCH = LocalDateTime.of(2021, 12, 29, 9, 2).atZone(ZoneId.systemDefault()).toInstant().toEpochMilli(); + private static final long SEQUENCE_BITS = 12L; + private static final long WORKER_ID_BITS = 10L; + static final long WORKER_ID_MAX_VALUE = 1024L; + private static final long SEQUENCE_MASK = 4095L; + private static final long WORKER_ID_LEFT_SHIFT_BITS = 12L; + private static final long TIMESTAMP_LEFT_SHIFT_BITS = 22L; + static Long WORKER_ID; + private static long SEQUENCE; + private static long LAST_TIME; + + public Id(Long workerId) { + WORKER_ID = workerId; + } + + public static long next() { + return nextKey(); + } + + public static String nextString() { + return String.valueOf(next()); + } + + private static synchronized long nextKey() { + long currentMillis = System.currentTimeMillis(); + Preconditions.checkState(LAST_TIME <= currentMillis, "Clock is moving backwards, last time is %d milliseconds, current time is %d milliseconds", LAST_TIME, currentMillis); + if (LAST_TIME == currentMillis) { + if (0L == (SEQUENCE = SEQUENCE + 1L & 4095L)) { + currentMillis = waitUntilNextTime(currentMillis); + } + } else { + SEQUENCE = 0L; + } + + LAST_TIME = currentMillis; + return currentMillis - EPOCH << 22 | WORKER_ID << 12 | SEQUENCE; + } + + private static long waitUntilNextTime(final long lastTime) { + long time; + for(time = System.currentTimeMillis(); time <= lastTime; time = System.currentTimeMillis()) { + } + + return time; + } +} diff --git a/bonus-common-biz/Id/src/main/java/net/xnzn/framework/id/IdProperties.java b/bonus-common-biz/Id/src/main/java/net/xnzn/framework/id/IdProperties.java new file mode 100644 index 0000000..bf8711b --- /dev/null +++ b/bonus-common-biz/Id/src/main/java/net/xnzn/framework/id/IdProperties.java @@ -0,0 +1,107 @@ +package net.xnzn.framework.id; + +import org.springframework.boot.context.properties.ConfigurationProperties; + +@ConfigurationProperties( + prefix = "id" +) +public class IdProperties { + public static final String PREFIX = "id"; + private Boolean enabled = true; + private String key = "worker_id_sequence"; + private String workspace; + + public Boolean getEnabled() { + return this.enabled; + } + + public String getKey() { + return this.key; + } + + public String getWorkspace() { + return this.workspace; + } + + public void setEnabled(final Boolean enabled) { + this.enabled = enabled; + } + + public void setKey(final String key) { + this.key = key; + } + + public void setWorkspace(final String workspace) { + this.workspace = workspace; + } + + public boolean equals(final Object o) { + if (o == this) { + return true; + } else if (!(o instanceof IdProperties)) { + return false; + } else { + IdProperties other = (IdProperties)o; + if (!other.canEqual(this)) { + return false; + } else { + label47: { + Object this$enabled = this.getEnabled(); + Object other$enabled = other.getEnabled(); + if (this$enabled == null) { + if (other$enabled == null) { + break label47; + } + } else if (this$enabled.equals(other$enabled)) { + break label47; + } + + return false; + } + + Object this$key = this.getKey(); + Object other$key = other.getKey(); + if (this$key == null) { + if (other$key != null) { + return false; + } + } else if (!this$key.equals(other$key)) { + return false; + } + + Object this$workspace = this.getWorkspace(); + Object other$workspace = other.getWorkspace(); + if (this$workspace == null) { + if (other$workspace != null) { + return false; + } + } else if (!this$workspace.equals(other$workspace)) { + return false; + } + + return true; + } + } + } + + protected boolean canEqual(final Object other) { + return other instanceof IdProperties; + } + + public int hashCode() { + int PRIME = true; + int result = 1; + Object $enabled = this.getEnabled(); + result = result * 59 + ($enabled == null ? 43 : $enabled.hashCode()); + Object $key = this.getKey(); + result = result * 59 + ($key == null ? 43 : $key.hashCode()); + Object $workspace = this.getWorkspace(); + result = result * 59 + ($workspace == null ? 43 : $workspace.hashCode()); + return result; + } + + public String toString() { + Boolean var10000 = this.getEnabled(); + return "IdProperties(enabled=" + var10000 + ", key=" + this.getKey() + ", workspace=" + this.getWorkspace() + ")"; + } +} diff --git a/bonus-common-biz/Id/src/main/java/net/xnzn/framework/id/IdWorkAutoConfiguration.java b/bonus-common-biz/Id/src/main/java/net/xnzn/framework/id/IdWorkAutoConfiguration.java new file mode 100644 index 0000000..8deee3b --- /dev/null +++ b/bonus-common-biz/Id/src/main/java/net/xnzn/framework/id/IdWorkAutoConfiguration.java @@ -0,0 +1,169 @@ +package net.xnzn.framework.id; + +import cn.hutool.core.text.CharSequenceUtil; +import java.io.File; +import java.io.IOException; +import java.io.RandomAccessFile; +import java.nio.channels.FileChannel; +import java.nio.channels.FileLock; +import java.nio.charset.StandardCharsets; +import java.util.Collection; +import java.util.Iterator; +import java.util.UUID; +import org.apache.commons.io.FileUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.boot.autoconfigure.AutoConfiguration; +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.data.redis.core.StringRedisTemplate; +import org.springframework.util.CollectionUtils; + +@AutoConfiguration( + after = {RedisAutoConfiguration.class} +) +@ConditionalOnClass({StringRedisTemplate.class}) +@EnableConfigurationProperties({IdProperties.class}) +@ConditionalOnProperty( + prefix = "id", + name = {"enabled"}, + havingValue = "true", + matchIfMissing = true +) +public class IdWorkAutoConfiguration { + private static final Logger log = LoggerFactory.getLogger(IdWorkAutoConfiguration.class); + private final IdProperties idProperties; + + public IdWorkAutoConfiguration(StringRedisTemplate redisTemplate, IdProperties idProperties) throws IOException { + this.idProperties = idProperties; + Long workerId = this.getLocalWorkId(); + + try { + while(workerId == null) { + Long newWorkId = redisTemplate.opsForValue().increment(idProperties.getKey(), 1L); + this.saveLocalWorkId(String.valueOf(newWorkId)); + workerId = this.getLocalWorkId(); + } + } catch (Throwable var5) { + log.error("获取workID失败", var5); + throw var5; + } + + if (workerId > 1024L) { + throw new RuntimeException("超过最大启动实例"); + } else { + Id.WORKER_ID = workerId; + } + } + + private void saveLocalWorkId(String workId) throws IOException { + File workIdHome = this.getWorkIdHome(); + String var10002 = String.valueOf(workIdHome.getAbsoluteFile()); + FileUtils.writeStringToFile(new File(var10002 + "/" + String.valueOf(UUID.randomUUID()) + ".lock"), workId, StandardCharsets.UTF_8); + } + + private File getWorkIdHome() { + String workHome = this.idProperties.getWorkspace(); + if (CharSequenceUtil.isBlank(workHome)) { + workHome = FileUtils.getUserDirectoryPath() + "/.workId/"; + } + + String var10002 = CharSequenceUtil.removeSuffix(workHome, "/"); + return new File(var10002 + "/" + this.idProperties.getKey()); + } + + private Long getLocalWorkId() throws IOException { + File workIdHome = this.getWorkIdHome(); + if (!workIdHome.exists()) { + return null; + } else { + Collection files = FileUtils.listFiles(workIdHome, new String[]{"lock"}, false); + if (CollectionUtils.isEmpty(files)) { + return null; + } else { + Iterator var3 = files.iterator(); + + while(true) { + if (var3.hasNext()) { + File file = (File)var3.next(); + FileChannel channel = null; + FileLock fileLock = null; + boolean var13 = false; + + Long var8; + label112: { + try { + var13 = true; + RandomAccessFile randomAccessFile = new RandomAccessFile(file, "rw"); + channel = randomAccessFile.getChannel(); + fileLock = channel.tryLock(); + if (fileLock != null) { + var8 = Long.valueOf(randomAccessFile.readLine()); + var13 = false; + break label112; + } + + var13 = false; + } finally { + if (var13) { + if (fileLock == null) { + if (channel != null) { + channel.close(); + } + } else { + Runtime.getRuntime().addShutdownHook(new Thread(() -> { + try { + channel.close(); + } catch (IOException var2) { + log.error("Release WorkId file lock error", var2); + } + + })); + } + + } + } + + if (fileLock == null) { + if (channel != null) { + channel.close(); + } + } else { + Runtime.getRuntime().addShutdownHook(new Thread(() -> { + try { + channel.close(); + } catch (IOException var2) { + log.error("Release WorkId file lock error", var2); + } + + })); + } + continue; + } + + if (fileLock == null) { + if (channel != null) { + channel.close(); + } + } else { + Runtime.getRuntime().addShutdownHook(new Thread(() -> { + try { + channel.close(); + } catch (IOException var2) { + log.error("Release WorkId file lock error", var2); + } + + })); + } + + return var8; + } + + return null; + } + } + } + } +}