1. Общ преглед
UUID (Универсално уникален идентификатор), известен също като GUID (Глобално уникален идентификатор) представлява 128-битова дълга стойност, която е уникална за всички практически цели . Стандартното представяне на UUID използва шестнадесетични цифри (октети):
123e4567-e89b-12d3-a456-556642440000
UUID се състои от шестнадесетични цифри (по 4 символа всяка) заедно с 4 символа "-", които правят дължината му равна на 36 знака .
Nil UUID е специална форма на UUID, при която всички битове са зададени на нула.
В тази статия ще разгледаме UUID класа в Java. Първо ще разгледаме как да използваме самия клас. След това ще разгледаме различните видове UUID и как можем да ги генерираме в Java.
2. UUID Class
Класът UUID има един конструктор:
UUID uuid = new UUID(long mostSignificant64Bits, long leastSignificant64Bits);
Ако искаме да използваме този конструктор, трябва да предоставим две дълги стойности. Това обаче изисква от нас да изградим сами битовия модел за UUID.
За удобство има три статични метода за създаване на UUID. Това са:
UUID uuid = UUID.nameUUIDFromBytes(byte[] bytes);
Този метод създава UUID версия 3 от дадения байтов масив.
UUID uuid = UUID.randomUUID();
Методът randomUUID () създава UUID версия 4. Това е най-удобният начин за създаване на UUID.
UUID uuid = UUID.fromString(String uuidHexDigitString);
Третият статичен метод връща UUID обект, като е представено низовото представяне на даден UUID.
Нека сега разгледаме как е структуриран UUID.
3. Структура
Да вземем примера UUID:
123e4567-e89b-42d3-a456-556642440000 xxxxxxxx-xxxx-Bxxx-Axxx-xxxxxxxxxxxx
3.1. UUID вариант
A представлява вариантът, който определя оформлението на UUID. Всички други битове в UUID зависят от настройката на битовете в полето за вариант. Вариантът се определя от 3 най-значими бита от A:
MSB1 MSB2 MSB3 0 X X reserved (0) 1 0 X current variant (2) 1 1 0 reserved for Microsoft (6) 1 1 1 reserved for future (7)
Стойността на A в споменатия UUID е „a“. Бинарният еквивалент на „a“ (= 10xx) показва варианта като 2.
3.2. UUID версия
B представлява версията. Версията в споменатия UUID (стойност на B ) е 4.
Java предоставя методи за получаване на вариант и версия на UUID:
UUID uuid = UUID.randomUUID(); int variant = uuid.variant(); int version = uuid.version();
Това са 5 различни версии за UUID на вариант 2: Времева основа (UUIDv1), DCE защита (UUIDv2), Име на база (UUIDv3 и UUIDv5), Случайна (UUIDv4).
Java осигурява изпълнение за v3 и v4, но също така осигурява конструктор за генериране на всякакъв тип UUID:
UUID uuid = new UUID(long mostSigBits, long leastSigBits);
4. Версиите на UUID
4.1. Версия 1
UUID версия 1 се основава на текущия клеймо, измерено в единици от 100 наносекунди от 15 октомври 1582 г., обединено с MAC адреса на устройството, където е създаден UUID.
Ако поверителността е проблем, UUID версия 1 може алтернативно да бъде генерирана с произволен 48-битов номер вместо MAC адреса.
В тази статия ще използваме тази алтернатива. Първо ще генерираме 64-те най-малки и най-значими бита като дълги стойности:
private static long get64LeastSignificantBitsForVersion1() { Random random = new Random(); long random63BitLong = random.nextLong() & 0x3FFFFFFFFFFFFFFFL; long variant3BitFlag = 0x8000000000000000L; return random63BitLong + variant3BitFlag; } private static long get64MostSignificantBitsForVersion1() { LocalDateTime start = LocalDateTime.of(1582, 10, 15, 0, 0, 0); Duration duration = Duration.between(start, LocalDateTime.now()); long seconds = duration.getSeconds(); long nanos = duration.getNano(); long timeForUuidIn100Nanos = seconds * 10000000 + nanos * 100; long least12SignificatBitOfTime = (timeForUuidIn100Nanos & 0x000000000000FFFFL) >> 4; long version = 1 << 12; return (timeForUuidIn100Nanos & 0xFFFFFFFFFFFF0000L) + version + least12SignificatBitOfTime; }
След това можем да предадем тези две стойности на конструктора на UUID:
public static UUID generateType1UUID() { long most64SigBits = get64MostSignificantBitsForVersion1(); long least64SigBits = get64LeastSignificantBitsForVersion1(); return new UUID(most64SigBits, least64SigBits); }
4.2. Версия 2
Версия 2 се основава на времеви клей и MAC адреса. RFC 4122 обаче не посочва точните подробности за генерирането, поради което няма да разглеждаме изпълнение в тази статия.
4.3. Версия 3 и 5
UUID се генерират с помощта на хеш на пространство от имена и име. Идентификаторите на пространството от имена са UUID като Система за имена на домейни (DNS), Идентификатори на обекти (OID), URL адреси и т.н.
UUID = hash(NAMESPACE_IDENTIFIER + NAME)
Единствената разлика между UUIDv3 и UUIDv5 е алгоритъмът на хеширане - v3 използва MD5 (128 бита), докато v5 използва SHA-1 (160 бита).
Просто казано, ние съкращаваме получения хеш на 128 бита и след това заместваме 4 бита за версията и 2 бита за варианта.
Нека генерираме UUID от тип 3:
byte[] nameSpaceBytes = bytesFromUUID(namespace); byte[] nameBytes = name.getBytes("UTF-8"); byte[] result = joinBytes(nameSpaceBytes, nameBytes); UUID uuid = UUID.nameUUIDFromBytes(result);
Тук е важно да се отбележи, че шестнадесетичният низ за пространството от имена първо трябва да бъде преобразуван в байтов масив.
Java не осигурява изпълнението за тип 5. Проверете хранилището на изходния ни код за UUIDv5.
4.4. Версия 4
Реализацията UUID v4 използва произволни числа като източник. Реализацията на Java е SecureRandom - която използва непредсказуема стойност като семе за генериране на случайни числа, за да намали вероятността от сблъсъци.
Нека генерираме версия 4 UUID:
UUID uuid = UUID.randomUUID();
Нека генерираме уникален ключ, използвайки 'SHA-256' и произволен UUID:
MessageDigest salt = MessageDigest.getInstance("SHA-256"); salt.update(UUID.randomUUID().toString().getBytes("UTF-8")); String digest = bytesToHex(salt.digest());
5. Заключение
В тази статия видяхме как е структуриран UUID, кои варианти и версии има. Научихме за кои версии Java предлага внедрена версия и разгледахме примери за кодове, за да генерираме другите версии.
И както винаги, изходният код за изпълнение е достъпен на Github.