Leitfaden zur UUID in Java

1. Übersicht

UUID (Universally Unique Identifier), auch als GUID (Globally Unique Identifier) ​​bekannt, repräsentiert einen 128 Bit langen Wert, der für alle praktischen Zwecke eindeutig ist . Die Standarddarstellung der UUID verwendet hexadezimale Ziffern (Oktette):

123e4567-e89b-12d3-a456-556642440000

Eine UUID besteht aus hexadezimalen Ziffern (jeweils 4 Zeichen) und 4 "-" - Symbolen, deren Länge 36 Zeichen entspricht .

Die Null-UUID ist eine spezielle Form der UUID, bei der alle Bits auf Null gesetzt werden.

In diesem Artikel werfen wir einen Blick auf die UUID- Klasse in Java. Zuerst schauen wir uns an, wie die Klasse selbst verwendet wird. Anschließend werden wir uns die verschiedenen Arten von UUIDs ansehen und wie wir sie in Java generieren können.

2. Die UUID- Klasse

Die UUID-Klasse hat einen einzelnen Konstruktor:

UUID uuid = new UUID(long mostSignificant64Bits, long leastSignificant64Bits);

Wenn wir diesen Konstruktor verwenden möchten, müssen wir zwei lange Werte angeben. Es erfordert jedoch, dass wir das Bitmuster für die UUID selbst erstellen.

Der Einfachheit halber gibt es drei statische Methoden zum Erstellen einer UUID. Diese sind:

UUID uuid = UUID.nameUUIDFromBytes(byte[] bytes); 

Diese Methode erstellt eine UUID der Version 3 aus dem angegebenen Byte-Array.

UUID uuid = UUID.randomUUID(); 

Die randomUUID () -Methode erstellt eine UUID der Version 4. Dies ist die bequemste Methode zum Erstellen einer UUID.

UUID uuid = UUID.fromString(String uuidHexDigitString); 

Die dritte statische Methode gibt ein UUID-Objekt mit der Zeichenfolgendarstellung einer bestimmten UUID zurück.

Schauen wir uns nun an, wie eine UUID aufgebaut ist.

3. Struktur

Nehmen wir das Beispiel UUID:

123e4567-e89b-42d3-a456-556642440000 xxxxxxxx-xxxx-Bxxx-Axxx-xxxxxxxxxxxx

3.1. UUID-Variante

A stellt die Variante dar, die das Layout der UUID bestimmt. Alle anderen Bits in der UUID hängen von der Einstellung der Bits im Variantenfeld ab. Die Variante wird durch 3 höchstwertige Bits von A bestimmt:

 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)

Der Wert von A in der genannten UUID ist 'a'. Das binäre Äquivalent von 'a' (= 10xx) zeigt die Variante als 2.

3.2. UUID-Version

B steht für die Version. Die Version in der genannten UUID (Wert von B ) ist 4.

Java bietet Methoden zum Abrufen der Variante und Version der UUID:

UUID uuid = UUID.randomUUID(); int variant = uuid.variant(); int version = uuid.version();

Dies sind 5 verschiedene Versionen für UUIDs der Variante 2: Zeitbasiert (UUIDv1), DCE-Sicherheit (UUIDv2), Namensbasiert (UUIDv3 und UUIDv5), Zufällig (UUIDv4).

Java bietet eine Implementierung für v3 und v4, aber auch einen Konstruktor zum Generieren eines beliebigen UUID-Typs:

UUID uuid = new UUID(long mostSigBits, long leastSigBits);

4. Die UUID-Versionen

4.1. Version 1

UUID Version 1 basiert auf dem aktuellen Zeitstempel, gemessen in Einheiten von 100 Nanosekunden ab dem 15. Oktober 1582, verkettet mit der MAC-Adresse des Geräts, auf dem die UUID erstellt wurde.

Wenn Datenschutz ein Problem darstellt, kann UUID Version 1 alternativ mit einer zufälligen 48-Bit-Nummer anstelle der MAC-Adresse generiert werden.

In diesem Artikel werden wir diese Alternative. Zuerst generieren wir die 64 kleinsten und höchstwertigen Bits als lange Werte:

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; }

Wir können diese beiden Werte dann an den Konstruktor der UUID übergeben:

public static UUID generateType1UUID() { long most64SigBits = get64MostSignificantBitsForVersion1(); long least64SigBits = get64LeastSignificantBitsForVersion1(); return new UUID(most64SigBits, least64SigBits); }

4.2. Version 2

Version 2 basiert ebenfalls auf einem Zeitstempel und der MAC-Adresse. In RFC 4122 werden jedoch nicht die genauen Generierungsdetails angegeben. Daher wird in diesem Artikel keine Implementierung behandelt.

4.3. Version 3 & 5

Die UUIDs werden mit dem Hash von Namespace und Name generiert. Die Namespace-IDs sind UUIDs wie DNS (Domain Name System), OIDs (Object Identifiers), URLs usw.

UUID = hash(NAMESPACE_IDENTIFIER + NAME)

Der einzige Unterschied zwischen UUIDv3 und UUIDv5 ist der Hashing-Algorithmus - v3 verwendet MD5 (128 Bit), während v5 SHA-1 (160 Bit) verwendet.

Einfach ausgedrückt, wir kürzen den resultierenden Hash auf 128 Bit und ersetzen dann 4 Bit für die Version und 2 Bit für die Variante.

Lassen Sie uns eine UUID vom Typ 3 generieren:

byte[] nameSpaceBytes = bytesFromUUID(namespace); byte[] nameBytes = name.getBytes("UTF-8"); byte[] result = joinBytes(nameSpaceBytes, nameBytes); UUID uuid = UUID.nameUUIDFromBytes(result);

Hierbei ist zu beachten, dass die Hex-Zeichenfolge für den Namespace zuerst in ein Byte-Array konvertiert werden muss.

Java bietet die Implementierung für Typ 5 nicht an. Überprüfen Sie unser Quellcode-Repository auf UUIDv5.

4.4. Version 4

Die UUID v4-Implementierung verwendet Zufallszahlen als Quelle. Die Java-Implementierung ist SecureRandom. Dabei wird ein unvorhersehbarer Wert als Startwert verwendet, um Zufallszahlen zu generieren und die Wahrscheinlichkeit von Kollisionen zu verringern.

Lassen Sie uns die UUID der Version 4 generieren:

UUID uuid = UUID.randomUUID();

Lassen Sie uns einen eindeutigen Schlüssel mit 'SHA-256' und einer zufälligen UUID generieren:

MessageDigest salt = MessageDigest.getInstance("SHA-256"); salt.update(UUID.randomUUID().toString().getBytes("UTF-8")); String digest = bytesToHex(salt.digest());

5. Schlussfolgerung

In diesem Artikel haben wir gesehen, wie eine UUID aufgebaut ist, welche Varianten und Versionen es gibt. Wir haben erfahren, für welche Versionen Java eine sofort einsatzbereite Implementierung bietet, und uns Codebeispiele angesehen, um die anderen Versionen zu generieren.

Und wie immer ist der Quellcode der Implementierung auf Github verfügbar.