介绍
UUID(Universally Unique Identifier,通用唯一识别码),由32位16进制数字构成,二进制共128位。
其目的是让分布式系统中的所有元素都能有唯一的识别信息。如此一来,每个人都可以创建不与其它人冲突的 UUID。
组成
UUID共有5部分组成:xxxxxxxx-xxxx-Mxxx-Nxxx-xxxxxxxxxxxx
,表现形式为8-4-4-4-12的32个字符。
如:df623885-68f9-47e0-b13c-bbd9600b6e71
- 16进制数字
M
表示UUID版本,当前有5个版本:1,2,3,4,5。这5个版本使用不同算法,利用不同的信息产生UUID,各版本有各自优势,适用于不同情景。具体使用的信息:
- version 1, date-time & MAC address,当前时间戳 + MAC地址信息 生成
- 机器的MAC地址出厂后不能保证完全唯一,且之后 MAC 地址也可手动修改;
- MAC 地址的暴露会造成了隐私与安全问题;
- 若一台机子上的两个进程同时跑,有可能出现重复问题。
- version 2, date-time & group/user id
- version 3, MD5 hash & namespace
- version 4, pseudo-random number,伪随机数信息 生成,最频繁使用
- version 5, SHA-1 hash & namespace
- 16进制数字
N
的二进制位一至四个最高有效位表示UUID变体(variant),有固定的两位10xx
因此只可能取值8, 9, a, b - 因为时间戳和随机数的唯一性,版本1和版本4总是生成唯一的标识符。若希望对给定的一个字符串总是能生成相同的 UUID,使用版本3或版本5。
Java实现
java.util.UUID
封装了UUID的实现,来看看其中方法:
/**
* Static factory to retrieve a type 4 (pseudo randomly generated) UUID.
*
* The {@code UUID} is generated using a cryptographically strong pseudo
* random number generator.
*
* @return A randomly generated {@code UUID}
*/
public static UUID randomUUID() {
// 与Random(弱伪随机数生成器)不一样,SecureRandom是强伪随机数生成器,结果不可预测
// 使用SecureRandom生成随机数,替换version和variant就是 UUID
SecureRandom ng = Holder.numberGenerator;
byte[] randomBytes = new byte[16];
ng.nextBytes(randomBytes);
randomBytes[6] &= 0x0f; /* clear version */
randomBytes[6] |= 0x40; /* set to version 4 */
randomBytes[8] &= 0x3f; /* clear variant */
randomBytes[8] |= 0x80; /* set to IETF variant */
return new UUID(randomBytes);
}
可以从randomUUID()
看到,这个UUID应该是基于随机数的,版本4的UUID。
/**
* Static factory to retrieve a type 3 (name based) {@code UUID} based on
* the specified byte array.
*
* @param name
* A byte array to be used to construct a {@code UUID}
*
* @return A {@code UUID} generated from the specified array
*/
public static UUID nameUUIDFromBytes(byte[] name) {
MessageDigest md;
try {
md = MessageDigest.getInstance("MD5");
} catch (NoSuchAlgorithmException nsae) {
throw new InternalError("MD5 not supported", nsae);
}
byte[] md5Bytes = md.digest(name);
md5Bytes[6] &= 0x0f; /* clear version */
md5Bytes[6] |= 0x30; /* set to version 3 */
md5Bytes[8] &= 0x3f; /* clear variant */
md5Bytes[8] |= 0x80; /* set to IETF variant */
return new UUID(md5Bytes);
}
可以从nameUUIDFromBytes(byte[] name)
看到,这个UUID应该是基于MD5和命名空间,版本3的UUID。对于给定的字符串(name)总能生成相同的UUID。
参考: