programing

Java에서 GUID 생성

kingscode 2022. 8. 25. 22:08
반응형

Java에서 GUID 생성

Java에서 GUID를 작성하는 가장 좋은 방법은 무엇입니까?

java.util.UUID.randomUUID();

Java 5 이후에 번들된 UUID 클래스를 확인합니다.

예를 들어 다음과 같습니다.

  • 임의 UUID를 원하는 경우 임의 UUID를 사용할 수 있습니다.UUID 방식
  • UUID를 특정 값으로 초기화하는 경우 UUID 컨스트럭터 또는 fromString 메서드를 사용할 수 있습니다.

Mark Byers의 답변을 예로 들어 설명하겠습니다.

import java.util.UUID;

public class RandomStringUUID {
    public static void main(String[] args) {
        UUID uuid = UUID.randomUUID();
        System.out.println("UUID=" + uuid.toString() );
    }
}

원하는 UUID의 종류에 따라 달라집니다.

  • 표준 Java 클래스는 버전 4(랜덤) UUID를 생성합니다(UPDATE - 버전 3(이름) UUID도 생성할 수 있습니다).다른 변형도 처리할 수 있지만 생성할 수는 없습니다.(이 경우 "handle"은 구성을 의미합니다.)UUID(또는 표현으로부터의 인스턴스(instance) 및 적절한 접근자 제공)를 참조해 주세요.

  • Java UUID Generator(JUG) 실장은 "RFC-4122에 의해 정의된3가지 '공식' 타입의 UUID를 모두 지원한다고 주장하지만 실제로는 RFC가 4가지 타입을 정의하고 5번째 타입을 언급하고 있습니다.

UUID 유형 및 변형에 대한 자세한 내용은 위키피디아에 요약되어 있으며, 자세한 내용은 RFC 4122 및 기타 사양에 나와 있습니다.

다른 답변은 맞습니다. 특히 Stephen C의 답변입니다.

Java 외부 도달

Java 내에서 UUID 값을 생성하는 것은 보안상의 문제로 버전4(랜덤)로 제한됩니다.

다른 버전의 UUID를 원하는 경우 Java 앱이 JVM 외부에 도달하여 다음을 호출하여 UUID를 생성하도록 하는 방법이 있습니다.

  • 명령줄 유틸리티
    거의 모든 운영체제에 번들되어 있습니다.
    예를 들어 Mac OS X, BSD 및 Linux에 있습니다.
  • 데이터베이스 서버
    데이터베이스 서버에서 생성된 UUID를 가져오려면 JDBC를 사용합니다.
    예를 들어 Postgres에 번들되어 있는 확장자 등입니다.이 확장에 의해 버전1, 3, 및 4의 값이 생성될 수 있습니다.또, 다음의 몇개의 바리에이션도 생성할 수 있습니다.
  • uuid_generate_v1mc()– 버전 1 UUID를 생성하지만 컴퓨터의 실제 MAC 주소가 아닌 랜덤 멀티캐스트 MAC 주소를 사용합니다.
  • uuid_generate_v5(namespace uuid, name text)–는 SHA-1이 해시 방식으로 사용되는 것을 제외하고 버전3 UUID와 동일하게 동작하는 버전5 UUID를 생성합니다.
  • 웹 서비스
    를 들어 UUID Generator는 버전1과 버전3 및 제로값과 GUID를 만듭니다.

이 답변에는 RFC-4122에 준거한 랜덤베이스 및 이름베이스 UUID용 2개의 제너레이터가 포함되어 있습니다.자유롭게 사용하고 공유하세요.

랜덤 베이스(v4)

랜덤 기반 UUID를 생성하는 다음 유틸리티 클래스:

package your.package.name;

import java.security.SecureRandom;
import java.util.Random;
import java.util.UUID;

/**
 * Utility class that creates random-based UUIDs.
 * 
 */
public abstract class RandomUuidCreator {

    private static final int RANDOM_VERSION = 4;

    /**
     * Returns a random-based UUID.
     * 
     * It uses a thread local {@link SecureRandom}.
     * 
     * @return a random-based UUID
     */
    public static UUID getRandomUuid() {
        return getRandomUuid(SecureRandomLazyHolder.THREAD_LOCAL_RANDOM.get());
    }

    /**
     * Returns a random-based UUID.
     * 
     * It uses any instance of {@link Random}.
     * 
     * @return a random-based UUID
     */
    public static UUID getRandomUuid(Random random) {

        long msb = 0;
        long lsb = 0;

        // (3) set all bit randomly
        if (random instanceof SecureRandom) {
            // Faster for instances of SecureRandom
            final byte[] bytes = new byte[16];
            random.nextBytes(bytes);
            msb = toNumber(bytes, 0, 8); // first 8 bytes for MSB
            lsb = toNumber(bytes, 8, 16); // last 8 bytes for LSB
        } else {
            msb = random.nextLong(); // first 8 bytes for MSB
            lsb = random.nextLong(); // last 8 bytes for LSB
        }

        // Apply version and variant bits (required for RFC-4122 compliance)
        msb = (msb & 0xffffffffffff0fffL) | (RANDOM_VERSION & 0x0f) << 12; // apply version bits
        lsb = (lsb & 0x3fffffffffffffffL) | 0x8000000000000000L; // apply variant bits

        // Return the UUID
        return new UUID(msb, lsb);
    }

    private static long toNumber(final byte[] bytes, final int start, final int length) {
        long result = 0;
        for (int i = start; i < length; i++) {
            result = (result << 8) | (bytes[i] & 0xff);
        }
        return result;
    }

    // Holds thread local secure random
    private static class SecureRandomLazyHolder {
        static final ThreadLocal<Random> THREAD_LOCAL_RANDOM = ThreadLocal.withInitial(SecureRandom::new);
    }

    /**
     * For tests!
     */
    public static void main(String[] args) {

        System.out.println("// Using thread local `java.security.SecureRandom` (DEFAULT)");
        System.out.println("RandomUuidCreator.getRandomUuid()");
        System.out.println();
        for (int i = 0; i < 5; i++) {
            System.out.println(RandomUuidCreator.getRandomUuid());
        }

        System.out.println();
        System.out.println("// Using `java.util.Random` (FASTER)");
        System.out.println("RandomUuidCreator.getRandomUuid(new Random())");
        System.out.println();
        Random random = new Random();
        for (int i = 0; i < 5; i++) {
            System.out.println(RandomUuidCreator.getRandomUuid(random));
        }
    }
}

출력은 다음과 같습니다.

// Using thread local `java.security.SecureRandom` (DEFAULT)
RandomUuidCreator.getRandomUuid()

'ef4f5ad2-8147-46cb-8389-c2b8c3ef6b10'
'adc0305a-df29-4f08-9d73-800fde2048f0'
'4b794b59-bff8-4013-b656-5d34c33f4ce3'
'22517093-ee24-4120-96a5-ecee943992d1'
'899fb1fb-3e3d-4026-85a8-8a2d274a10cb'

// Using `java.util.Random` (FASTER)
RandomUuidCreator.getRandomUuid(new Random())

'4dabbbc2-fcb2-4074-a91c-5e2977a5bbf8'
'078ec231-88bc-4d74-9774-96c0b820ceda'
'726638fa-69a6-4a18-b09f-5fd2a708059b'
'15616ebe-1dfd-4f5c-b2ed-cea0ac1ad823'
'affa31ad-5e55-4cde-8232-cddd4931923a'

이름 기반(v3 및 v5)

이름 기반 UUID(MD5 및 SHA1)를 생성하는 다음 유틸리티 클래스:

package your.package.name;

import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.UUID;

/**
 * Utility class that creates UUIDv3 (MD5) and UUIDv5 (SHA1).
 *
 */
public class HashUuidCreator {

    // Domain Name System
    public static final UUID NAMESPACE_DNS = new UUID(0x6ba7b8109dad11d1L, 0x80b400c04fd430c8L);
    // Uniform Resource Locator
    public static final UUID NAMESPACE_URL = new UUID(0x6ba7b8119dad11d1L, 0x80b400c04fd430c8L);
    // ISO Object ID
    public static final UUID NAMESPACE_ISO_OID = new UUID(0x6ba7b8129dad11d1L, 0x80b400c04fd430c8L);
    // X.500 Distinguished Name
    public static final UUID NAMESPACE_X500_DN = new UUID(0x6ba7b8149dad11d1L, 0x80b400c04fd430c8L);

    private static final int VERSION_3 = 3; // UUIDv3 MD5
    private static final int VERSION_5 = 5; // UUIDv5 SHA1

    private static final String MESSAGE_DIGEST_MD5 = "MD5"; // UUIDv3
    private static final String MESSAGE_DIGEST_SHA1 = "SHA-1"; // UUIDv5

    private static UUID getHashUuid(UUID namespace, String name, String algorithm, int version) {

        final byte[] hash;
        final MessageDigest hasher;

        try {
            // Instantiate a message digest for the chosen algorithm
            hasher = MessageDigest.getInstance(algorithm);

            // Insert name space if NOT NULL
            if (namespace != null) {
                hasher.update(toBytes(namespace.getMostSignificantBits()));
                hasher.update(toBytes(namespace.getLeastSignificantBits()));
            }

            // Generate the hash
            hash = hasher.digest(name.getBytes(StandardCharsets.UTF_8));

            // Split the hash into two parts: MSB and LSB
            long msb = toNumber(hash, 0, 8); // first 8 bytes for MSB
            long lsb = toNumber(hash, 8, 16); // last 8 bytes for LSB

            // Apply version and variant bits (required for RFC-4122 compliance)
            msb = (msb & 0xffffffffffff0fffL) | (version & 0x0f) << 12; // apply version bits
            lsb = (lsb & 0x3fffffffffffffffL) | 0x8000000000000000L; // apply variant bits

            // Return the UUID
            return new UUID(msb, lsb);

        } catch (NoSuchAlgorithmException e) {
            throw new RuntimeException("Message digest algorithm not supported.");
        }
    }

    public static UUID getMd5Uuid(String string) {
        return getHashUuid(null, string, MESSAGE_DIGEST_MD5, VERSION_3);
    }

    public static UUID getSha1Uuid(String string) {
        return getHashUuid(null, string, MESSAGE_DIGEST_SHA1, VERSION_5);
    }

    public static UUID getMd5Uuid(UUID namespace, String string) {
        return getHashUuid(namespace, string, MESSAGE_DIGEST_MD5, VERSION_3);
    }

    public static UUID getSha1Uuid(UUID namespace, String string) {
        return getHashUuid(namespace, string, MESSAGE_DIGEST_SHA1, VERSION_5);
    }

    private static byte[] toBytes(final long number) {
        return new byte[] { (byte) (number >>> 56), (byte) (number >>> 48), (byte) (number >>> 40),
                (byte) (number >>> 32), (byte) (number >>> 24), (byte) (number >>> 16), (byte) (number >>> 8),
                (byte) (number) };
    }

    private static long toNumber(final byte[] bytes, final int start, final int length) {
        long result = 0;
        for (int i = start; i < length; i++) {
            result = (result << 8) | (bytes[i] & 0xff);
        }
        return result;
    }

    /**
     * For tests!
     */
    public static void main(String[] args) {

        String string = "JUST_A_TEST_STRING";
        UUID namespace = UUID.randomUUID(); // A custom name space

        System.out.println("Java's generator");
        System.out.println("UUID.nameUUIDFromBytes():      '" + UUID.nameUUIDFromBytes(string.getBytes()) + "'");
        System.out.println();
        System.out.println("This generator");
        System.out.println("HashUuidCreator.getMd5Uuid():  '" + HashUuidCreator.getMd5Uuid(string) + "'");
        System.out.println("HashUuidCreator.getSha1Uuid(): '" + HashUuidCreator.getSha1Uuid(string) + "'");
        System.out.println();
        System.out.println("This generator WITH name space");
        System.out.println("HashUuidCreator.getMd5Uuid():  '" + HashUuidCreator.getMd5Uuid(namespace, string) + "'");
        System.out.println("HashUuidCreator.getSha1Uuid(): '" + HashUuidCreator.getSha1Uuid(namespace, string) + "'");
    }
}

출력은 다음과 같습니다.

// Java's generator
UUID.nameUUIDFromBytes():      '9e120341-627f-32be-8393-58b5d655b751'

// This generator
HashUuidCreator.getMd5Uuid():  '9e120341-627f-32be-8393-58b5d655b751'
HashUuidCreator.getSha1Uuid(): 'e4586bed-032a-5ae6-9883-331cd94c4ffa'

// This generator WITH name space
HashUuidCreator.getMd5Uuid():  '2b098683-03c9-3ed8-9426-cf5c81ab1f9f'
HashUuidCreator.getSha1Uuid(): '1ef568c7-726b-58cc-a72a-7df173463bbb'

대체 발전기

이 경우에도 하실 수 있습니다.uuid-creator 예를 해 주세요이치노

// Create a random-based UUID
UUID uuid = UuidCreator.getRandomBased();
// Create a name based UUID (SHA1)
String name = "JUST_A_TEST_STRING";
UUID uuid = UuidCreator.getNameBasedSha1(name);

프로젝트 페이지: https://github.com/f4b6a3/uuid-creator

대부분의 경우 개체에 대한 글로벌 UUID가 필요하며, 특히 이벤트 기반 아키텍처 또는 이벤트 소싱에서는 날짜를 기준으로 이벤트를 정렬해야 하지만 타임스탬프에 대한 전체 정보는 필요하지 않습니다.

사전 편찬으로 정렬 있는 ULID 구현 중 하나를 사용할 수 있습니다.

형식은 표준 UUID와 다르지만 다음과 같이 단순합니다.

example value: 01AN4Z07BY79KA1307SR9X4MV3

 01AN4Z07BY      79KA1307SR9X4MV3

|----------|    |----------------|
 Timestamp          Randomness
   48bits             80bits

여러 언어로 구현되어 있습니다.

예를 들어 Java에서는 이를 위한 simple lib가 있습니다.

코드 예:

import de.huxhorn.sulky.ulid.ULID;

ULID ulid = new ULID();

// with current timestamp
String newId = ulid.nextULID(); 

// with selected timestamp
String newId2 = ulid.nextULID(Instant
    .parse("2021-12-01T00:00:00.00Z")
    .toEpochMilli()
); 

Spring을 사용하면 ULID 제너레이터용 Bean도 만들 수 있습니다.

@Configuration
public class UUIDGeneratorConfig {

    @Bean
    public ULID ulidGenerator() {
        return new ULID();
    }
}
@Component
public class ULIDGenerator {

    private final ULID ulid;

    public ULIDGenerator(ULID ulid) {
        this.ulid = ulid;
    }

    public String generateUUID() {
        return ulid.nextULID();
    }

    public String generateUUID(Instant timestamp) {
        return ulid.nextULID(timestamp.toEpochMilli());
    }
}

언급URL : https://stackoverflow.com/questions/2982748/create-a-guid-in-java

반응형