Panduan untuk UUID di Java

1. Ikhtisar

UUID (Pengenal Unik Secara Universal), juga dikenal sebagai GUID (Pengenal Unik Secara Global) mewakili nilai panjang 128-bit yang unik untuk semua tujuan praktis . Representasi standar UUID menggunakan digit hex (oktet):

123e4567-e89b-12d3-a456-556642440000

UUID terdiri dari digit hex (masing-masing 4 karakter) bersama dengan 4 simbol “-” yang panjangnya sama dengan 36 karakter .

UUID Nil adalah bentuk khusus UUID di mana semua bit disetel ke nol.

Pada artikel ini, kita akan melihat kelas UUID di Java. Pertama, kita akan melihat bagaimana menggunakan kelas itu sendiri. Kemudian, kita akan melihat berbagai jenis UUID dan bagaimana kita bisa membuatnya di Java.

2. Kelas UUID

Kelas UUID memiliki satu konstruktor:

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

Jika kita ingin menggunakan konstruktor ini, kita perlu memberikan dua nilai panjang. Namun, hal itu mengharuskan kami untuk membuat sendiri pola bit untuk UUID.

Untuk kenyamanan, ada tiga metode statis untuk membuat UUID. Ini adalah:

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

Metode ini membuat UUID versi 3 dari array byte yang diberikan.

UUID uuid = UUID.randomUUID(); 

Metode randomUUID () membuat UUID versi 4. Ini adalah cara paling nyaman untuk membuat UUID.

UUID uuid = UUID.fromString(String uuidHexDigitString); 

Metode statis ketiga mengembalikan objek UUID yang diberi representasi string dari UUID tertentu.

Sekarang mari kita lihat bagaimana UUID disusun.

3. Struktur

Mari kita ambil contoh UUID:

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

3.1. UUID Varian

A mewakili varian yang menentukan tata letak UUID. Semua bit lain di UUID bergantung pada setelan bit di kolom varian. Varian ditentukan oleh 3 bit paling signifikan dari 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)

Nilai A dalam UUID tersebut adalah 'a'. Persamaan biner dari 'a' (= 10xx) menunjukkan varian sebagai 2.

3.2. Versi UUID

B mewakili versinya. Versi dalam UUID yang disebutkan (nilai B ) adalah 4.

Java menyediakan metode untuk mendapatkan varian dan versi UUID:

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

Ini adalah 5 versi berbeda untuk varian 2 UUID: Berbasis Waktu (UUIDv1), DCE Security (UUIDv2), Berbasis Nama (UUIDv3 dan UUIDv5), Acak (UUIDv4).

Java menyediakan implementasi untuk v3 dan v4, tetapi juga menyediakan konstruktor untuk menghasilkan segala jenis UUID:

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

4. Versi UUID

4.1. Versi 1

UUID versi 1 didasarkan pada stempel waktu saat ini, diukur dalam satuan 100 nanodetik dari tanggal 15 Oktober 1582, digabungkan dengan alamat MAC perangkat tempat UUID dibuat.

Jika privasi menjadi masalah, UUID versi 1 dapat dibuat dengan nomor 48-bit acak alih-alih alamat MAC.

Pada artikel ini, kami akan alternatif ini. Pertama, kita akan menghasilkan 64 bit paling kecil dan paling signifikan sebagai nilai panjang:

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

Kami kemudian dapat meneruskan dua nilai ini ke konstruktor UUID:

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

4.2. Versi 2

Versi 2 didasarkan pada stempel waktu dan alamat MAC juga. Namun, RFC 4122 tidak menentukan detail pembuatan yang tepat, oleh karena itu, kami tidak akan melihat penerapannya di artikel ini.

4.3. Versi 3 & 5

UUID dibuat menggunakan hash namespace dan nama. Pengidentifikasi namespace adalah UUID seperti Domain Name System (DNS), Object Identifiers (OIDs), URL, dll.

UUID = hash(NAMESPACE_IDENTIFIER + NAME)

Satu-satunya perbedaan antara UUIDv3 dan UUIDv5 adalah Algoritma Hashing - v3 menggunakan MD5 (128 bit) sedangkan v5 menggunakan SHA-1 (160 bit).

Sederhananya, kami memotong hash yang dihasilkan menjadi 128-bit dan kemudian mengganti 4 bit untuk versi dan 2 bit untuk varian.

Mari buat UUID tipe 3:

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

Di sini, penting untuk dicatat bahwa hex-string untuk namespace harus terlebih dahulu diubah menjadi array byte.

Java tidak menyediakan implementasi untuk tipe 5. Periksa repositori kode sumber kami untuk UUIDv5.

4.4. Versi 4

Implementasi UUID v4 menggunakan angka acak sebagai sumber. Implementasi Java adalah SecureRandom - yang menggunakan nilai yang tidak dapat diprediksi sebagai seed untuk menghasilkan angka acak guna mengurangi kemungkinan tabrakan.

Mari buat UUID versi 4:

UUID uuid = UUID.randomUUID();

Mari buat kunci unik menggunakan 'SHA-256' dan UUID acak:

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

5. Kesimpulan

Dalam artikel ini, kami melihat bagaimana UUID disusun, varian dan versinya. Kami mempelajari versi Java mana yang menyediakan implementasi out-of-the-box, dan melihat contoh kode untuk menghasilkan versi lain.

Dan, seperti biasa, kode sumber implementasi tersedia di Github.