objectId生成可读性唯一ID

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

mongodb objectId分析

01234567891011
time时间戳machine机器信息pid进程IDinc随机数

保证在同一时间可以生成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<NetworkInterface> 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());
    }

}

  • 8
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值