objectId生成可读性唯一ID

基于mongodb objectId书写的生成唯一ID

mongodb objectId分析

0 1 2 3 4 5 6 7 8 9 10 11
time时间戳 machine机器信息 pid进程ID inc随机数

保证在同一时间可以生成256^3个ID
参考源码:mongo-java-driver

java书写的ObjectId生成策略

import java.net.NetworkInterface;
import java.nio.ByteBuffer;
import java.util.Enumeration;
import java.util.Random;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * 仿照mongodb objectId书写
 * @author 曲修成
 * @className ObjectId
 * @description
 * @date 2017-01-04 12:58:00
 */
public class ObjectId {

    /**
     * 线程安全的下一个随机数,每次生成自增+1
     */
    // 随机
    private static AtomicInteger nextInc = new AtomicInteger((new java.util.Random()).nextInt());
    //不随机
    //private static AtomicInteger nextInc = new AtomicInteger();


    /**
     * 机器信息
     */
    private static final int machine;

    /**
     * 初始化机器信息 = 机器码 + 进程码
     */
    static {
        try {
            // 机器码
            int machinePiece;
            try {
                StringBuilder netSb = new StringBuilder();
                // 返回机器所有的网络接口
                Enumeration e = NetworkInterface.getNetworkInterfaces();
                // 遍历网络接口
                while (e.hasMoreElements()) {
                    NetworkInterface ni = e.nextElement();
                    // 网络接口信息
                    netSb.append(ni.toString());
                }
                // 保留后两位
                machinePiece = netSb.toString().hashCode() << 16;
            } catch (Throwable e) {
                // 出问题随机生成,保留后两位
                machinePiece = (new Random().nextInt()) << 16;
            }
            // 进程码
            // 因为静态变量类加载可能相同,所以要获取进程ID + 加载对象的ID值
            final int processPiece;
            // 进程ID初始化
            int processId = new java.util.Random().nextInt();
            try {
                // 获取进程ID
                processId = java.lang.management.ManagementFactory.getRuntimeMXBean().getName().hashCode();
            } catch (Throwable t) {
            }

            ClassLoader loader = ObjectId.class.getClassLoader();

            // 返回对象哈希码,无论是否重写hashCode方法
            int loaderId = loader != null ? System.identityHashCode(loader) : 0;

            // 进程ID + 对象加载ID
            StringBuilder processSb = new StringBuilder();
            processSb.append(Integer.toHexString(processId));
            processSb.append(Integer.toHexString(loaderId));
            // 保留前2位
            processPiece = processSb.toString().hashCode() & 0xFFFF;

            // 生成机器信息 = 取机器码的后2位和进程码的前2位
            machine = machinePiece | processPiece;

        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 获取一个objectId 
     * @title next
     * @description
     * @author 曲修成
     * @date 2017-01-04 04:25:32
     * @param
     * @return java.lang.String objectId
     */
    public static String next(){

        byte b[] = new byte[12];
        ByteBuffer bb = ByteBuffer.wrap(b);
        bb.putInt((int) (System.currentTimeMillis() / 1000));//4位
        bb.putInt(machine);//4位
        bb.putInt(nextInc.getAndIncrement());//4位
        StringBuilder buf = new StringBuilder(24);
        // 原来objectId格式化太慢
        for (byte t : bb.array()) {
            // 小于两位左端补0
            int i = t & 0xff;
            if (i < 16) {
                buf.append("0").append(Integer.toHexString(i));
            }else {
                buf.append(Integer.toHexString(i));
            }

        }
        return buf.toString();
    }

    /**
     * 获取一个objectId用下划线分割
     * @title nextWithUnderline
     * @description
     * @author 曲修成
     * @date 2017-01-04 04:25:53
     * @param
     * @return java.lang.String objectId
     */
    public static String nextWithUnderline(){

        byte b[] = new byte[12];
        ByteBuffer bb = ByteBuffer.wrap(b);
        bb.putInt((int) (System.currentTimeMillis() / 1000));//4位
        bb.putInt(machine);//4位
        bb.putInt(nextInc.getAndIncrement());//4位
        StringBuilder buf = new StringBuilder(24);
        // 原来objectId格式化太慢
        byte[] array = bb.array();
        for (int i = 0; i < array.length; i++) {
            if (i % 4 == 0 && i != 0) {
                buf.append("-");
            }
            int t = array[i] & 0xff;
            if (t < 16) {
                buf.append("0").append(Integer.toHexString(t));
            }else {
                buf.append(Integer.toHexString(t));
            }

        }
        return buf.toString();
    }

    public static void main(String[] args) {
        System.out.println(ObjectId.next());
    }

}

你可能感兴趣的:(objectId生成可读性唯一ID)