mirror of
https://gitee.com/chinabugotech/hutool.git
synced 2025-04-19 03:01:48 +08:00
add methods
This commit is contained in:
parent
478b523c67
commit
73764db818
@ -0,0 +1,75 @@
|
||||
/*
|
||||
* Copyright (c) 2024. looly(loolly@aliyun.com)
|
||||
* Hutool is licensed under Mulan PSL v2.
|
||||
* You can use this software according to the terms and conditions of the Mulan PSL v2.
|
||||
* You may obtain a copy of Mulan PSL v2 at:
|
||||
* https://license.coscl.org.cn/MulanPSL2
|
||||
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
|
||||
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
||||
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
||||
* See the Mulan PSL v2 for more details.
|
||||
*/
|
||||
|
||||
package org.dromara.hutool.core.data.id;
|
||||
|
||||
import org.dromara.hutool.core.util.RandomUtil;
|
||||
|
||||
/**
|
||||
* ID相关常量
|
||||
*
|
||||
* @author Looly
|
||||
* @since 5.8.28
|
||||
*/
|
||||
public class IdConstants {
|
||||
/**
|
||||
* 默认的数据中心ID。
|
||||
* <p>此常量通过调用{@link IdUtil#getDataCenterId(long)}方法,传入{@link Snowflake#MAX_DATA_CENTER_ID}作为参数,
|
||||
* 来获取一个默认的数据中心ID。它在系统中作为一个全局配置使用,标识系统默认运行在一个最大数据中心ID限定的环境中。</p>
|
||||
*
|
||||
* @see IdUtil#getDataCenterId(long)
|
||||
* @see Snowflake#MAX_DATA_CENTER_ID
|
||||
*/
|
||||
public static final long DEFAULT_DATACENTER_ID = IdUtil.getDataCenterId(Snowflake.MAX_DATA_CENTER_ID);
|
||||
|
||||
/**
|
||||
* 默认的Worker ID生成。
|
||||
* <p>这个静态常量是通过调用IdUtil的getWorkerId方法,使用默认的数据中心ID和Snowflake算法允许的最大Worker ID来获取的。</p>
|
||||
*
|
||||
* @see IdUtil#getWorkerId(long, long) 获取Worker ID的具体实现方法
|
||||
* @see Snowflake#MAX_WORKER_ID Snowflake算法中定义的最大Worker ID
|
||||
*/
|
||||
public static final long DEFAULT_WORKER_ID = IdUtil.getWorkerId(DEFAULT_DATACENTER_ID, Snowflake.MAX_WORKER_ID);
|
||||
|
||||
/**
|
||||
* 默认的节点ID。
|
||||
* 这个方法是静态的,且最终返回的节点ID是基于数据中心ID生成,生成失败则使用随机数
|
||||
*/
|
||||
public static final long DEFAULT_SEATA_NODE_ID = generateNodeId();
|
||||
|
||||
/**
|
||||
* 默认的Snowflake单例,使用默认的Worker ID和数据中心ID。<br>
|
||||
* 传入{@link #DEFAULT_WORKER_ID}和{@link #DEFAULT_DATACENTER_ID}作为参数。<br>
|
||||
* 此单例对象保证在同一JVM实例中获取ID唯一,唯一性使用进程ID和MAC地址保证。
|
||||
*/
|
||||
public static final Snowflake DEFAULT_SNOWFLAKE = new Snowflake(DEFAULT_WORKER_ID, DEFAULT_DATACENTER_ID);
|
||||
|
||||
/**
|
||||
* 默认的Seata单例,使用默认的节点ID。<br>
|
||||
* 传入{@link #DEFAULT_SEATA_NODE_ID}作为参数。<br>
|
||||
* 此单例对象保证在同一JVM实例中获取ID唯一,唯一性使用进程ID和MAC地址保证。
|
||||
*/
|
||||
public static final SeataSnowflake DEFAULT_SEATA_SNOWFLAKE = new SeataSnowflake(DEFAULT_SEATA_NODE_ID);
|
||||
|
||||
/**
|
||||
* 基于网卡MAC地址生成节点ID,失败则使用随机数
|
||||
*
|
||||
* @return nodeId
|
||||
*/
|
||||
private static long generateNodeId() {
|
||||
try {
|
||||
return IdUtil.getDataCenterId(SeataSnowflake.MAX_NODE_ID);
|
||||
} catch (final Exception e) {
|
||||
return RandomUtil.randomLong(SeataSnowflake.MAX_NODE_ID + 1);
|
||||
}
|
||||
}
|
||||
}
|
@ -33,7 +33,7 @@ import org.dromara.hutool.core.util.RuntimeUtil;
|
||||
*/
|
||||
public class IdUtil {
|
||||
|
||||
// ------------------------------------------------------------------- UUID
|
||||
// region ----- UUID
|
||||
|
||||
/**
|
||||
* 获取随机UUID
|
||||
@ -73,6 +73,10 @@ public class IdUtil {
|
||||
return UUID.fastUUID().toString(true);
|
||||
}
|
||||
|
||||
// endregion
|
||||
|
||||
// region ----- ObjectId
|
||||
|
||||
/**
|
||||
* 创建MongoDB ID生成策略实现<br>
|
||||
* ObjectId由以下几部分组成:
|
||||
@ -92,6 +96,10 @@ public class IdUtil {
|
||||
return ObjectId.next();
|
||||
}
|
||||
|
||||
// endregion
|
||||
|
||||
// region ----- Snowflake
|
||||
|
||||
/**
|
||||
* 获取单例的Twitter的Snowflake 算法生成器对象<br>
|
||||
* 分布式系统中,有一些需要使用全局唯一ID的场景,有些时候我们希望能使用一种简单一些的ID,并且希望ID能够按照时间有序生成。
|
||||
@ -164,12 +172,64 @@ public class IdUtil {
|
||||
* 参考:<a href="http://www.cnblogs.com/relucent/p/4955340.html">http://www.cnblogs.com/relucent/p/4955340.html</a>
|
||||
*
|
||||
* @return {@link Snowflake}
|
||||
* @see IdConstants#DEFAULT_SNOWFLAKE
|
||||
* @since 5.7.3
|
||||
*/
|
||||
public static Snowflake getSnowflake() {
|
||||
return Singleton.get(Snowflake.class);
|
||||
return IdConstants.DEFAULT_SNOWFLAKE;
|
||||
}
|
||||
|
||||
/**
|
||||
* 简单获取Snowflake 的 nextId<br>
|
||||
* 终端ID 数据中心ID 默认为根据PID和MAC地址生成
|
||||
*
|
||||
* @return nextId
|
||||
* @since 5.7.18
|
||||
*/
|
||||
public static long getSnowflakeNextId() {
|
||||
return getSnowflake().next();
|
||||
}
|
||||
|
||||
/**
|
||||
* 简单获取Snowflake 的 nextId<br>
|
||||
* 终端ID 数据中心ID 默认为根据PID和MAC地址生成
|
||||
*
|
||||
* @return nextIdStr
|
||||
* @since 5.7.18
|
||||
*/
|
||||
public static String getSnowflakeNextIdStr() {
|
||||
return getSnowflake().nextStr();
|
||||
}
|
||||
|
||||
// endregion
|
||||
|
||||
// region ----- NanoId
|
||||
|
||||
/**
|
||||
* 获取随机NanoId
|
||||
*
|
||||
* @return 随机NanoId
|
||||
* @since 5.7.5
|
||||
*/
|
||||
public static String nanoId() {
|
||||
return NanoId.randomNanoId();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取随机NanoId
|
||||
*
|
||||
* @param size ID中的字符数量
|
||||
* @return 随机NanoId
|
||||
* @since 5.7.5
|
||||
*/
|
||||
public static String nanoId(final int size) {
|
||||
return NanoId.randomNanoId(size);
|
||||
}
|
||||
|
||||
// endregion
|
||||
|
||||
// region ----- DataCenterId and WorkerId
|
||||
|
||||
/**
|
||||
* 获取数据中心ID<br>
|
||||
* 数据中心ID依赖于本地网卡MAC地址。
|
||||
@ -229,49 +289,59 @@ public class IdUtil {
|
||||
return (mpid.toString().hashCode() & 0xffff) % (maxWorkerId + 1);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------- NanoId
|
||||
// endregion
|
||||
|
||||
// region ----- SeateSnowflake
|
||||
|
||||
/**
|
||||
* 获取随机NanoId
|
||||
* 获取默认的SeataSnowflake单例实例。
|
||||
*
|
||||
* @return 随机NanoId
|
||||
* @since 5.7.5
|
||||
* <p>该方法为静态方法,无需实例化对象即可调用。它返回的是一个默认配置的SeataSnowflake实例,
|
||||
* 可以直接用于生成分布式ID。在应用程序中,如果未显式设置自定义的SeataSnowflake实例,
|
||||
* 则会使用此默认实例。
|
||||
*
|
||||
* @return SeataSnowflake 返回一个默认配置的SeataSnowflake实例。
|
||||
*
|
||||
* @see IdConstants#DEFAULT_SNOWFLAKE
|
||||
*/
|
||||
public static String nanoId() {
|
||||
return NanoId.randomNanoId();
|
||||
public static SeataSnowflake getSeataSnowflake() {
|
||||
return IdConstants.DEFAULT_SEATA_SNOWFLAKE;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取随机NanoId
|
||||
* 获取SeataSnowflake单例实例。
|
||||
*
|
||||
* @param size ID中的字符数量
|
||||
* @return 随机NanoId
|
||||
* @since 5.7.5
|
||||
* <p>该方法为静态方法,无需实例化对象即可调用。它返回的是一个自定义配置的SeataSnowflake实例,
|
||||
* 可以用于生成具有特定节点ID的分布式ID。
|
||||
*
|
||||
* @param nodeId 节点ID
|
||||
* @return SeataSnowflake 返回一个自定义配置的SeataSnowflake实例。
|
||||
*
|
||||
* @see IdConstants#DEFAULT_SEATA_SNOWFLAKE
|
||||
*/
|
||||
public static String nanoId(final int size) {
|
||||
return NanoId.randomNanoId(size);
|
||||
public static SeataSnowflake getSeataSnowflake(final long nodeId) {
|
||||
return Singleton.get(SeataSnowflake.class, nodeId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 简单获取Snowflake 的 nextId
|
||||
* 终端ID 数据中心ID 默认为1
|
||||
* 简单获取SeataSnowflake 的 nextId<br>
|
||||
* NodeId默认为DataCenterId
|
||||
*
|
||||
* @return nextId
|
||||
* @since 5.7.18
|
||||
*/
|
||||
public static long getSnowflakeNextId() {
|
||||
return getSnowflake().next();
|
||||
public static long getSeataSnowflakeNextId() {
|
||||
return getSeataSnowflake().next();
|
||||
}
|
||||
|
||||
/**
|
||||
* 简单获取Snowflake 的 nextId
|
||||
* 终端ID 数据中心ID 默认为1
|
||||
* 简单获取SeataSnowflake 的 nextId<br>
|
||||
* NodeId默认为DataCenterId
|
||||
*
|
||||
* @return nextIdStr
|
||||
* @since 5.7.18
|
||||
*/
|
||||
public static String getSnowflakeNextIdStr() {
|
||||
return getSnowflake().nextStr();
|
||||
public static String getSeataSnowflakeNextIdStr() {
|
||||
return getSeataSnowflake().nextStr();
|
||||
}
|
||||
|
||||
// endregion
|
||||
}
|
||||
|
@ -14,7 +14,6 @@ package org.dromara.hutool.core.data.id;
|
||||
|
||||
import org.dromara.hutool.core.lang.generator.Generator;
|
||||
import org.dromara.hutool.core.text.StrUtil;
|
||||
import org.dromara.hutool.core.util.RandomUtil;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
@ -48,7 +47,7 @@ public class SeataSnowflake implements Generator<Long>, Serializable {
|
||||
// 节点ID长度
|
||||
private static final int NODE_ID_BITS = 10;
|
||||
// 节点ID的最大值,1023
|
||||
private final int MAX_NODE_ID = ~(-1 << NODE_ID_BITS);
|
||||
protected static final int MAX_NODE_ID = ~(-1 << NODE_ID_BITS);
|
||||
// 时间戳长度
|
||||
private static final int TIMESTAMP_BITS = 41;
|
||||
// 序列号12位(表示只允许序号的范围为:0-4095)
|
||||
@ -79,7 +78,7 @@ public class SeataSnowflake implements Generator<Long>, Serializable {
|
||||
* 构造
|
||||
*
|
||||
* @param epochDate 初始化时间起点(null表示默认起始日期),后期修改会导致id重复,如果要修改连workerId dataCenterId,慎用
|
||||
* @param nodeId 节点ID
|
||||
* @param nodeId 节点ID, 默认为DataCenterId或随机生成
|
||||
*/
|
||||
public SeataSnowflake(final Date epochDate, final Long nodeId) {
|
||||
final long twepoch = (null == epochDate) ? DEFAULT_TWEPOCH : epochDate.getTime();
|
||||
@ -117,7 +116,7 @@ public class SeataSnowflake implements Generator<Long>, Serializable {
|
||||
*/
|
||||
private void initNodeId(Long nodeId) {
|
||||
if (nodeId == null) {
|
||||
nodeId = generateNodeId();
|
||||
nodeId = IdConstants.DEFAULT_SEATA_NODE_ID;
|
||||
}
|
||||
if (nodeId > MAX_NODE_ID || nodeId < 0) {
|
||||
final String message = StrUtil.format("worker Id can't be greater than {} or less than 0", MAX_NODE_ID);
|
||||
@ -125,17 +124,4 @@ public class SeataSnowflake implements Generator<Long>, Serializable {
|
||||
}
|
||||
this.nodeId = nodeId << (TIMESTAMP_BITS + SEQUENCE_BITS);
|
||||
}
|
||||
|
||||
/**
|
||||
* 基于网卡MAC地址生成节点ID,失败则使用随机数
|
||||
*
|
||||
* @return workerId
|
||||
*/
|
||||
private long generateNodeId() {
|
||||
try {
|
||||
return IdUtil.getDataCenterId(MAX_NODE_ID);
|
||||
} catch (final Exception e) {
|
||||
return RandomUtil.randomLong(MAX_NODE_ID + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -54,10 +54,10 @@ public class Snowflake implements Generator<Long>, Serializable {
|
||||
public static final long DEFAULT_TWEPOCH = 1288834974657L;
|
||||
private static final long WORKER_ID_BITS = 5L;
|
||||
// 最大支持机器节点数0~31,一共32个
|
||||
private static final long MAX_WORKER_ID = ~(-1L << WORKER_ID_BITS);
|
||||
protected static final long MAX_WORKER_ID = ~(-1L << WORKER_ID_BITS);
|
||||
private static final long DATA_CENTER_ID_BITS = 5L;
|
||||
// 最大支持数据中心节点数0~31,一共32个
|
||||
private static final long MAX_DATA_CENTER_ID = ~(-1L << DATA_CENTER_ID_BITS);
|
||||
protected static final long MAX_DATA_CENTER_ID = ~(-1L << DATA_CENTER_ID_BITS);
|
||||
// 序列号12位(表示只允许序号的范围为:0-4095)
|
||||
private static final long SEQUENCE_BITS = 12L;
|
||||
// 机器节点左移12位
|
||||
@ -94,7 +94,7 @@ public class Snowflake implements Generator<Long>, Serializable {
|
||||
* 构造,使用自动生成的工作节点ID和数据中心ID
|
||||
*/
|
||||
public Snowflake() {
|
||||
this(IdUtil.getWorkerId(IdUtil.getDataCenterId(MAX_DATA_CENTER_ID), MAX_WORKER_ID));
|
||||
this(IdConstants.DEFAULT_WORKER_ID);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -103,7 +103,7 @@ public class Snowflake implements Generator<Long>, Serializable {
|
||||
* @param workerId 终端ID
|
||||
*/
|
||||
public Snowflake(final long workerId) {
|
||||
this(workerId, IdUtil.getDataCenterId(MAX_DATA_CENTER_ID));
|
||||
this(workerId, IdConstants.DEFAULT_DATACENTER_ID);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -13,8 +13,6 @@
|
||||
package org.dromara.hutool.core.data.id;
|
||||
|
||||
import org.dromara.hutool.core.collection.ConcurrentHashSet;
|
||||
import org.dromara.hutool.core.data.id.IdUtil;
|
||||
import org.dromara.hutool.core.data.id.Snowflake;
|
||||
import org.dromara.hutool.core.exception.HutoolException;
|
||||
import org.dromara.hutool.core.lang.Console;
|
||||
import org.dromara.hutool.core.lang.tuple.Pair;
|
||||
@ -83,6 +81,22 @@ public class SnowflakeTest {
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
@Disabled
|
||||
public void uniqueTest2(){
|
||||
// 测试并发环境下生成ID是否重复
|
||||
final Snowflake snowflake = IdUtil.getSnowflake();
|
||||
|
||||
final Set<Long> ids = new ConcurrentHashSet<>();
|
||||
ThreadUtil.concurrencyTest(100, () -> {
|
||||
for (int i = 0; i < 50000; i++) {
|
||||
if(!ids.add(snowflake.next())){
|
||||
throw new HutoolException("重复ID!");
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getSnowflakeLengthTest(){
|
||||
for (int i = 0; i < 1000; i++) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user