News:三分天注定,七分靠打拼,爱拼才会赢!致力打造专业IT博客。如果你对本博客有任何意见或建议请联系作者,邮箱:blog@caokuan.cn

Spring UUID 工具类 AlternativeJdkIdGenerator 分析

逝水无痕 346 0 条

UUID 在日常开发中使用的地方非常多,在作为唯一标识使用时非常方便。在 spring 框架4.0版本的工具包中多了一个 UUID 工具类 AlternativeJdkIdGenerator,这里主要分析一下这个工具类是如何生成 UUID 的。

uuid.jpg

AlternativeJdkIdGenerator 源码:

public class AlternativeJdkIdGenerator implements IdGenerator {

    private final Random random;


    public AlternativeJdkIdGenerator() {
        SecureRandom secureRandom = new SecureRandom();
        byte[] seed = new byte[8];
        secureRandom.nextBytes(seed);
        this.random = new Random(new BigInteger(seed).longValue());
    }


    @Override
    public UUID generateId() {
        byte[] randomBytes = new byte[16];
        this.random.nextBytes(randomBytes);

        long mostSigBits = 0;
        for (int i = 0; i < 8; i++) {
            mostSigBits = (mostSigBits << 8) | (randomBytes[i] & 0xff);
        }

        long leastSigBits = 0;
        for (int i = 8; i < 16; i++) {
            leastSigBits = (leastSigBits << 8) | (randomBytes[i] & 0xff);
        }

        return new UUID(mostSigBits, leastSigBits);
    }

}

分析

在构造函数中使用 SecureRandom 随机数对象生成随机数填满8长度的字节数组,然后将这个8字节的Long值作为种子创建 Random 对象。

在具体生成 UUID 过程中,首先使用随机数填满一个16长度的字节数组,然后对这个数组循环进行位运算。

在第一个位运算循环中:

(mostSigBits << 8) 表示 mostSigBits 左移8位
(randomBytes[i] & 0xff) 表示取字节数组中的某一个值的低8位

整个循环的含义就是:依次取字节数组中的值的低8位,然后由高位到地位依次排列组成一个8字节的 Long 型值。

第二个循环的原理同第一个循环。

两个循环结束后,就拿到了2个 Long 型值,然后作为 JDK 中的 UUID 类的构造参数,去生成 UUID。

JDK UUID toString() 方法分析

public String toString() {
    return (digits(mostSigBits >> 32, 8) + "-" +
            digits(mostSigBits >> 16, 4) + "-" +
            digits(mostSigBits, 4) + "-" +
            digits(leastSigBits >> 48, 4) + "-" +
            digits(leastSigBits, 12));
}

/** Returns val represented by the specified number of hex digits. */
private static String digits(long val, int digits) {
    long hi = 1L << (digits * 4);
    return Long.toHexString(hi | (val & (hi - 1))).substring(1);
}

我们最终是使用 UUID 的 toString() 方法生成的 UUID,所以这里再分析一下这个 toString() 方法。

digits(mostSigBits >> 32, 8) 为例分析:

long hi = 1L << (digits * 4); digits = 8 时,hi 值为
00000000 00000000 00000000 00000001 00000000 00000000 00000000 00000000

(hi - 1) 此时 hi - 1 的值为
00000000 00000000 00000000 00000000 11111111 11111111 11111111 11111111

(val & (hi - 1)) 的含义就是取 val 的低32位值

hi | (val & (hi - 1)) 则表示取低33位的值

Long.toHexString(hi | (val & (hi - 1))).substring(1) 将 Long 型值转为16进制字符串。其中每个字节生成2个字符。因为多出了一个 bit 位,所以会生成9个字符,substring(1) 之后就是8个字符了。

digits(long val, int digits) 方法源码中可以看出:第二个参数主要是用来控制&运算位数的。

后续的生成字符串的原理都是一致的。toString() 会生成如下结构的 ID 字符串:

8字符-4字符-4字符-4字符-12字符

如:cc5c2484-594e-c6b3-415e-246c19f50a3c

发表我的评论
icon_mrgreen.gificon_neutral.gificon_twisted.gificon_arrow.gificon_eek.gificon_smile.gificon_confused.gificon_cool.gificon_evil.gificon_biggrin.gificon_idea.gificon_redface.gificon_razz.gificon_rolleyes.gificon_wink.gificon_cry.gificon_surprised.gificon_lol.gificon_mad.gificon_sad.gificon_exclaim.gificon_question.gif

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址