package com.csw.shuanfa.utils.id;
import jodd.util.StringPool;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import java.lang.management.ManagementFactory;
import java.net.InetAddress;
import java.net.NetworkInterface;
/**
* 在線時間戳轉(zhuǎn)換工具 http://shijianchuo.wiicha.com/
* 雪花算法能保證69年不重復(fù)
* twitter的snowflake算法 -- java實現(xiàn)
默認使用是69年
如果要超過生成的會重復(fù)
可以適當(dāng)縮小數(shù)據(jù)中心位DATACENTER_BIT默認時5,時間戳位默認是41孽椰,
當(dāng)為DATACENTER_BIT為3的時候時間戳為是43可以用278年【當(dāng)然對應(yīng)的DATACENTER_BIT最大長度也會變短為7注意】
*
*
* @Autowired
* private SnowFlakeIdUtil snowFlakeIdUtil;
*
* //同一個機器上是單例【相當(dāng)于上了一把鎖一個一個進】昭娩,不同機器上分布式加鎖或者用網(wǎng)卡地址區(qū)分
* 相同服務(wù)之間最好指定不同的數(shù)據(jù)中心id和機器id
* // snowflake.datacenterId = 3
* // snowflake.machineId = 4
* // @Value("${snowflake.datacenterId}")
* // private long datacenterIdStr;
* //
* // @Value("${snowflake.machineId}")
* // private long machineIdStr;
* //
* // @Bean
* // public SnowFlakeIdUtil() {
* // //通過當(dāng)前物理網(wǎng)卡地址獲取datacenterId
* // this.datacenterId = datacenterIdStr;
* // //物理網(wǎng)卡地址+jvm進程pi獲取workerId
* // this.machineId = machineIdStr;
* // }
*
*/
@Component
public class SnowFlakeIdUtil {
private Logger logger = LoggerFactory.getLogger(ObjectIdUtil.class);
/**
* 起始的時間戳【系統(tǒng)開發(fā)的時候記得更改http://shijianchuo.wiicha.com/】
*/
private final long START_STMP = 1480166465631L;
/*
* 每一部分占用的位數(shù)
*/
/**
* 序列號占用的位數(shù)
*/
private final long SEQUENCE_BIT = 12;
/**
* 機器標(biāo)識占用的位數(shù)
*/
private final long MACHINE_BIT = 5;
/**
* 數(shù)據(jù)中心占用的位數(shù) 數(shù)據(jù)中心占用的位數(shù)默認是5位建議用4位【時間戳就會變?yōu)?2位】,可以使用139年】
*/
private final long DATACENTER_BIT = 4;
/**
* 每一部分的最大值
*/
private final long MAX_SEQUENCE = ~(-1L << SEQUENCE_BIT);
/**
* 支持的最大機器id弄屡,結(jié)果是31(這個移位算法可以很快的計算出幾位二進制數(shù)所能表示的最大十進制數(shù))
*/
private final long maxMachineId = -1L ^ (-1L << MACHINE_BIT);
/**
* 支持的最大數(shù)據(jù)標(biāo)識id题禀,結(jié)果是31
*/
private final long maxDatacenterId = -1L ^ (-1L << DATACENTER_BIT);
/**
* 每一部分向左的位移
*/
private final long MACHINE_LEFT = SEQUENCE_BIT;
private final long DATACENTER_LEFT = SEQUENCE_BIT + MACHINE_BIT;
private final long TIMESTMP_LEFT = DATACENTER_LEFT + DATACENTER_BIT;
/**
* 數(shù)據(jù)中心
*/
private final long datacenterId;
/**
* //機器標(biāo)識
*/
private final long machineId;
/**
* //序列號
*/
private long sequence = 0L;
/**
* 上一次時間戳
*/
private long lastStmp = -1L;
public SnowFlakeIdUtil(long datacenterId, long machineId) {
if (datacenterId <= maxDatacenterId && datacenterId >= 0L) {
if (machineId <= maxMachineId && machineId >= 0L) {
this.datacenterId = datacenterId;
this.machineId = machineId;
} else {
throw new IllegalArgumentException(StrUtil.format("datacenter Id can't be greater than {} or less than 0", new Object[]{maxMachineId}));
}
} else {
throw new IllegalArgumentException(StrUtil.format("worker Id can't be greater than {} or less than 0", new Object[]{maxDatacenterId}));
}
}
public SnowFlakeIdUtil() {
//通過當(dāng)前物理網(wǎng)卡地址獲取datacenterId
this.datacenterId = getDatacenterId(maxDatacenterId);
//物理網(wǎng)卡地址+jvm進程pi獲取workerId
this.machineId = getMaxMachineId(datacenterId, maxMachineId);
}
/**
* 產(chǎn)生下一個ID
*/
public synchronized long nextId() {
long currStmp = getNewstmp();
if (currStmp < lastStmp) {
throw new RuntimeException("Clock moved backwards. Refusing to generate id");
}
if (currStmp == lastStmp) {
//相同毫秒內(nèi),序列號自增
sequence = (sequence + 1) & MAX_SEQUENCE;
//同一毫秒的序列數(shù)已經(jīng)達到最大
if (sequence == 0L) {
currStmp = getNextMill();
}
} else {
//不同毫秒內(nèi)膀捷,序列號置為0
sequence = 0L;
}
lastStmp = currStmp;
/*
* //時間戳部分
* //數(shù)據(jù)中心部分
* //機器標(biāo)識部分
* //序列號部分
*/
return (currStmp - START_STMP) << TIMESTMP_LEFT
| datacenterId << DATACENTER_LEFT
| machineId << MACHINE_LEFT
| sequence;
}
private long getNextMill() {
long mill = getNewstmp();
while (mill <= lastStmp) {
mill = getNewstmp();
}
return mill;
}
private long getNewstmp() {
return System.currentTimeMillis();
}
protected long getDatacenterId(long maxDatacenterId) {
long id = 0L;
try {
//獲取本機(或者服務(wù)器ip地址)
//DESKTOP-123SDAD/192.168.1.87
InetAddress ip = InetAddress.getLocalHost();
NetworkInterface network = NetworkInterface.getByInetAddress(ip);
//一般不是null會進入else
if (network == null) {
id = 1L;
} else {
//獲取物理網(wǎng)卡地址
byte[] mac = network.getHardwareAddress();
if (null != mac) {
id = ((0x000000FF & (long) mac[mac.length - 2]) | (0x0000FF00 & (((long) mac[mac.length - 1]) << 8))) >> 6;
id = id % (maxDatacenterId + 1);
}
}
} catch (Exception e) {
logger.warn(" getDatacenterId: " + e.getMessage());
}
return id;
}
/**
* 獲取 maxWorkerId
*/
protected long getMaxMachineId(long datacenterId, long maxMachineId) {
StringBuilder mpid = new StringBuilder();
mpid.append(datacenterId);
//獲取jvm進程信息
String name = ManagementFactory.getRuntimeMXBean().getName();
if (StringUtils.isNotBlank(name)) {
/*
* 獲取進程PID
*/
mpid.append(name.split(StringPool.AT)[0]);
}
/*
* MAC + PID 的 hashcode 獲取16個低位
*/
return (mpid.toString().hashCode() & 0xffff) % (maxMachineId + 1);
}
}
轉(zhuǎn)62進制
//cn.hutool.core.util
private static final char[] BASE_62_CHARS = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz".toCharArray();
public static String SnowflakeIdtoBase62Id() {
Long snowflakeId = IdUtil.getSnowflake().nextId();
return longtoBase62Id(snowflakeId);
}
public static String longtoBase62Id(Long snowflakeId) {
StringBuilder base62 = new StringBuilder();
do {
int remainder = (int) (snowflakeId % 62);
base62.insert(0, BASE_62_CHARS[remainder]);
snowflakeId = snowflakeId / 62;
} while (snowflakeId > 0);
return base62.toString();
}
轉(zhuǎn)36進制
//cn.hutool.core.util
public static String getSnowflake_36() {
return Long.toUnsignedString(IdUtil.getSnowflake().nextId(), 36).toUpperCase();
}