Génération d'identifiants uniques globaux en Java : Exemples pratiques

Cet article présente des implémentations concrètes pour la génération d'identifiants uniques globaux (UID) en Java, en s'appuyant sur des projets open-source de Baidu et Meituan. Les principes théoriques étant largement documentés, nous nous concentrerons ici sur les aspects pratiques du code.

Générateur d'UID Baidu

Dépendance Maven

<dependency>
    <groupId>com.baidu.uid</groupId>
    <artifactId>uid-generator-sdk</artifactId>
    <version>1.0.15</version>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>8.0.28</version>
</dependency>

Schéma SQL pour le nœud worker

DROP TABLE IF EXISTS `worker_node`;
CREATE TABLE `worker_node` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'ID du worker',
  `host_name` varchar(64) NOT NULL COMMENT 'Nom d''hôte',
  `port` varchar(64) NOT NULL COMMENT 'Port',
  `type` int NOT NULL COMMENT 'Type de nœud',
  `launch_date` DATE NOT NULL COMMENT 'Date de lancement',
  `modified` timestamp NOT NULL COMMENT 'Date de modification',
  `created` timestamp NOT NULL COMMENT 'Date de création',
  PRIMARY KEY (`id`)
) COMMENT='Assigneur d''ID worker pour le générateur d''UID' ENGINE=InnoDB;

Configuration de l'application (application.yml)

spring:
  datasource:
    url: jdbc:mysql://localhost:3306/your_database
    username: your_username
    password: your_password
    driver-class-name: com.mysql.cj.jdbc.Driver

Configuration des Beans Spring

package com.example.uid.config;

import com.baidu.uid.generator.impl.DefaultUidGenerator;
import com.baidu.uid.worker.DisposableWorkerIdAssigner;
import com.baidu.uid.worker.WorkerIdAssigner;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class UidGeneratorConfig {

    @Bean
    public WorkerIdAssigner workerIdAssigner() {
        // Utilisation d'un assigneur basé sur une base de données, ou un autre mécanisme
        DisposableWorkerIdAssigner assigner = new DisposableWorkerIdAssigner();
        // Configuration de l'assigneur si nécessaire (ex: via JdbcTemplate)
        return assigner;
    }

    @Bean
    public DefaultUidGenerator defaultUidGenerator(WorkerIdAssigner workerIdAssigner) {
        DefaultUidGenerator uidGenerator = new DefaultUidGenerator();
        uidGenerator.setWorkerIdAssigner(workerIdAssigner);
        uidGenerator.setEpochStr("2023-01-01"); // Votre date d'époque
        uidGenerator.setTimeBits(30);
        uidGenerator.setWorkerBits(22);
        uidGenerator.setSeqBits(12);
        return uidGenerator;
    }
}

Exemple de test

package com.example.uid.test;

import com.baidu.uid.generator.impl.DefaultUidGenerator;
import com.baidu.uid.generator.utils.UidUtils;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

@SpringBootTest
public class UidGeneratorTest {

    @Autowired
    private DefaultUidGenerator defaultUidGenerator;

    @Test
    public void testGenerateUID() {
        long uniqueId = defaultUidGenerator.getUID();
        System.out.println("Generated UID: " + uniqueId);
        System.out.println("Parsed UID: " + UidUtils.parseUID(uniqueId));
    }
}

Générateur d'UID Meituan (Leaf)

Dépendance Maven

<dependency>
    <groupId>com.meituan.leaf</groupId>
    <artifactId>leaf-core</artifactId>
    <version>1.0.0</version>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>8.0.28</version>
</dependency>

Schéma SQL pour les segments ID

DROP TABLE IF EXISTS `id_segment`;
CREATE TABLE `id_segment` (
  `biz_tag` varchar(50) NOT NULL COMMENT 'Tag métier',
  `max_id` bigint(20) NOT NULL COMMENT 'ID maximum alloué',
  `step` bigint(20) NOT NULL COMMENT 'Taille du segment',
  `last_update_time` datetime DEFAULT NULL,
  `current_update_time` datetime DEFAULT NULL,
  PRIMARY KEY (`biz_tag`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Table de stockage des segments d''ID';

INSERT INTO `id_segment` (`biz_tag`, `max_id`, `step`, `last_update_time`, `current_update_time`) VALUES ('Order', 1000, 100, NOW(), NOW());

Configuration des Beans Spring

package com.example.uid.config;

import com.meituan.leaf.common.Result;
import com.meituan.leaf.common.Status;
import com.meituan.leaf.jdbc.impl.MySqlLeafImpl;
import com.meituan.leaf.segment.SegmentService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.core.JdbcTemplate;

@Configuration
public class LeafConfig {

    @Autowired
    private JdbcTemplate jdbcTemplate;

    @Bean
    public SegmentService segmentService() {
        MySqlLeafImpl mysqlLeaf = new MySqlLeafImpl();
        mysqlLeaf.setJdbcTemplate(jdbcTemplate);
        mysqlLeaf.setBizTag("Order"); // Le tag métier de votre choix
        mysqlLeaf.setCacheEnabled(true); // Activer la mise en cache des segments
        return mysqlLeaf;
    }

    // Méthode utilitaire pour obtenir un ID, encapsulant la logique de Leaf
    public long getOrderId() {
        SegmentService service = segmentService(); // Note: Ceci devrait être un bean injecté
        Result result = service.getId("Order");
        if (result.getStatus() == Status.EXCEPTION) {
            throw new RuntimeException("Failed to get ID from Leaf: " + result.getMessage());
        }
        return result.getId();
    }
}

Exemple de test

package com.example.uid.test;

import com.example.uid.config.LeafConfig;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

@SpringBootTest
public class LeafTest {

    @Autowired
    private LeafConfig leafConfig; // Injecter la configuration qui contient la logique pour obtenir l'ID

    @Test
    public void testGenerateOrderId() {
        long orderId = leafConfig.getOrderId();
        System.out.println("Generated Order ID: " + orderId);
    }
}

Ces exemples fournissent une base pour implémenter des générateurs d'UID dans vos applications Java. Le projet Baidu est généralement apprécié pour sa simplicité et ses performances, tandis que Leaf de Meituan offre une appproche basée sur des segmetns gérés en base de données.

Étiquettes: Java uid uniqueidgenerator Baidu meituan

Publié le 1 août à 05h27