Java 的 ID 生成器(工具類)
阿新 • • 發佈:2019-02-10
使用業務場景
1. 資料庫自增主鍵無法滿足
2. 分散式系統的ID生成
3. 需要按照時間生成唯一ID
4. 無序的唯一ID
import java.lang.management.ManagementFactory;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.security.MessageDigest;
import java.util.UUID;
/**
* 用於生產各種各樣的ID
*/
public class IdUtils {
private static String middle = "";
static {
middle = MathUtils.makeUpNewData(Math.abs(NetworkUtils.getHostIP().hashCode()) + "", 4) + //4位IP地址hash
MathUtils.makeUpNewData(NetworkUtils.getPid(), 4); //4位PID程序hash
}
/**
* 以毫微秒做基礎計數, 返回唯一有序增長ID
* <pre>System.nanoTime()</pre>
* <pre>
* 執行緒數量: 100
* 執行次數: 1000
* 平均耗時: 222 ms
* 陣列長度: 100000
* Map Size: 100000
* </pre>
* @return ID長度32位
*/
public static String getIncreaseIdByNanoTime(){
return System.nanoTime()+ //時間戳-14位
middle+ //標誌-8位
MathUtils.makeUpNewData(Thread.currentThread().hashCode()+"" , 3)+ //3位執行緒標誌
MathUtils.randomDigitNumber(7); //隨機7位數
}
/**
* 以毫秒做基礎計數, 返回唯一有序增長ID, 有機率出現執行緒併發
* <pre>System.currentTimeMillis()</pre>
* <pre>
* 執行緒數量: 100
* 執行次數: 1000
* 平均耗時: 206 ms
* 陣列長度: 100000
* Map Size: 99992
* </pre>
* @return ID長度32位
*/
public static String getIncreaseIdByCurrentTimeMillis(){
return System.currentTimeMillis()+ //時間戳-14位
middle+ //標誌-8位
MathUtils.makeUpNewData(Thread.currentThread().hashCode()+"", 3)+ //3位執行緒標誌
MathUtils.randomDigitNumber(8); //隨機8位數
}
/**
* 基於UUID+MD5產生唯一無序ID
* <pre>
* 執行緒數量: 100
* 執行次數: 1000
* 平均耗時: 591 ms
* 陣列長度: 100000
* Map Size: 100000
* </pre>
* @return ID長度32位
*/
public static String getRandomIdByUUID(){
return DigestUtils.md5Hex(UUID.randomUUID().toString());
}
/* ---------------------------------------------分割線------------------------------------------------ */
/** 字串MD5處理類 */
private static class DigestUtils {
private static final char[] DIGITS_LOWER =
{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
private static final char[] DIGITS_UPPER =
{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
private static char[] encodeHex(final byte[] data, final char[] toDigits) {
final int l = data.length;
final char[] out = new char[l << 1];
for (int i = 0, j = 0; i < l; i++) {
out[j++] = toDigits[(0xF0 & data[i]) >>> 4];
out[j++] = toDigits[0x0F & data[i]];
}
return out;
}
public static String md5Hex(String str){
return md5Hex(str, false);
}
public static String md5Hex(String str, boolean isUpper){
try {
return new String(encodeHex(MessageDigest.getInstance("MD5").digest(str.getBytes("UTF-8")), isUpper ? DIGITS_UPPER : DIGITS_LOWER));
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
/* ---------------------------------------------分割線------------------------------------------------ */
/** 網路相關的處理類 */
private static class NetworkUtils {
private static final String DEFAULT_HOST_IP = "10.10.10.10";
/**
* 獲取當前程序的PID
*/
public static String getPid(){
return ManagementFactory.getRuntimeMXBean().getName().split("@")[0];
}
/**
* 獲取當前程序的主機IP地址
*/
public static String getHostIP(){
try {
return InetAddress.getLocalHost().getHostAddress();
} catch (UnknownHostException e) {
return DEFAULT_HOST_IP;
}
}
}
/* ---------------------------------------------分割線------------------------------------------------ */
/** 資料處理的相關類 */
private static class MathUtils {
private static final String DEFAULT_DIGITS = "0";
private static final String FIRST_DEFAULT_DIGITS = "1";
/**
* @param target 目標數字
* @param length 需要補充到的位數, 補充預設數字[0], 第一位預設補充[1]
* @return 補充後的結果
*/
public static String makeUpNewData(String target, int length){
return makeUpNewData(target, length, DEFAULT_DIGITS);
}
/**
* @param target 目標數字
* @param length 需要補充到的位數
* @param add 需要補充的數字, 補充預設數字[0], 第一位預設補充[1]
* @return 補充後的結果
*/
public static String makeUpNewData(String target, int length, String add){
if(target.startsWith("-")) target.replace("-", "");
if(target.length() >= length) return target.substring(0, length);
StringBuffer sb = new StringBuffer(FIRST_DEFAULT_DIGITS);
for (int i = 0; i < length - (1 + target.length()); i++) {
sb.append(add);
}
return sb.append(target).toString();
}
/**
* 生產一個隨機的指定位數的字串數字
* @param length
* @return
*/
public static String randomDigitNumber(int length){
int start = Integer.parseInt(makeUpNewData("", length));//1000+8999=9999
int end = Integer.parseInt(makeUpNewData("", length + 1)) - start;//9000
return (int)(Math.random() * end) + start + "";
}
}
}