Spring Boot 集成全局唯一ID生成器

叁歲伎倆 2023-10-11 16:47 109阅读 0赞

介绍

源码地址

UidGenerator是Java实现的,基于Snowflake算法的唯一ID生成器。

UidGenerator以组件形式工作在应用项目中,支持自定义workerId位数和初始化策略,从而适用于docker等虚拟化环境下实例自动重启、漂移等场景。

在实现上,UidGenerator通过借用未来时间来解决sequence天然存在的并发限制;采用RingBuffer来缓存已生成的UID,并行化UID的生产和消费,同时对CacheLine补齐,避免了由RingBuffer带来的硬件级「伪共享」问题,最终单机QPS可达600万。

打包源码

打包源码
打包成功

导包

注意事项:请在需要集成UidGenerator的项目进行导包操作,输入如下命令进行如下操作进行导包,注意修改jar包位置

  1. mvn install:install-file -Dfile=/opt/uid-generator-1.0.0-SNAPSHOT.jar -DgroupId=com.generator -DartifactId=uid-generator -Dversion=1.0.0-SNAPSHOT -Dpackaging=jar

执行导包操作
输入命令
导入成功

引入依赖

注意事项:由于UidGenerator默认集成了MyBatis和MyBatis Spring相关依赖,本项目使用的是MyBatis Plus,因此要把MyBatis和MyBatis Spring的依赖排除。

  1. <dependency>
  2. <groupId>com.generator</groupId>
  3. <artifactId>uid-generator</artifactId>
  4. <version>1.0.0-SNAPSHOT</version>
  5. <exclusions>
  6. <exclusion>
  7. <groupId>org.mybatis</groupId>
  8. <artifactId>mybatis</artifactId>
  9. </exclusion>
  10. <exclusion>
  11. <groupId>org.mybatis</groupId>
  12. <artifactId>mybatis-spring</artifactId>
  13. </exclusion>
  14. </exclusions>
  15. </dependency>
  16. <dependency>
  17. <groupId>commons-lang</groupId>
  18. <artifactId>commons-lang</artifactId>
  19. <version>2.6</version>
  20. </dependency>

创建数据表

  1. DROP TABLE IF EXISTS `worker_node`;
  2. CREATE TABLE `worker_node` (
  3. `work_node_id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键',
  4. `host_name` varchar(64) NOT NULL COMMENT '主机名称',
  5. `port` varchar(64) NOT NULL COMMENT '端口',
  6. `type` int NOT NULL COMMENT '类型(ACTUAL or CONTAINER)',
  7. `launch_date` date NOT NULL COMMENT '年月日',
  8. `create_time` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间',
  9. `update_time` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '修改时间',
  10. PRIMARY KEY (`work_node_id`) USING BTREE
  11. ) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;

创建实体类

  1. @Data
  2. @TableName("worker_node")
  3. public class WorkNode {
  4. @TableId(value = "work_node_id", type = IdType.AUTO)
  5. private Long workNodeId;
  6. /**
  7. * 主机名称
  8. */
  9. private String hostName;
  10. /**
  11. * 端口
  12. */
  13. private String port;
  14. /**
  15. * 类型(ACTUAL or CONTAINER)
  16. */
  17. private Integer type;
  18. /**
  19. * 年月日
  20. */
  21. private Date launchDate;
  22. /**
  23. * 创建时间
  24. */
  25. private Date createTime;
  26. /**
  27. * 修改时间
  28. */
  29. @TableField(update = "now()")
  30. private Date updateTime;
  31. }

创建持久层

  1. @Repository
  2. public interface WorkerNodeMapper extends BaseMapper<WorkNode> {
  3. }

创建接口及实现类

  1. public interface WorkNodeService extends IService<WorkNodeDO> {
  2. WorkNodeDO getWorkerNodeByHostPort(String host, String port);
  3. void insertWorkerNode(WorkNodeDO workNode);
  4. }
  5. @Service
  6. public class WorkNodeServiceImpl extends ServiceImpl<WorkerNodeMapper, WorkNodeDO> implements WorkNodeService {
  7. @Override
  8. public WorkNodeDO getWorkerNodeByHostPort(String host, String port) {
  9. return null;
  10. }
  11. @Override
  12. public void insertWorkerNode(WorkNodeDO workNode) {
  13. }
  14. }

创建UidGenerator配置类

  1. public class DisposableWorkerIdAssigner implements WorkerIdAssigner {
  2. @Autowired
  3. private WorkNodeService workNodeService;
  4. /**
  5. * Assign worker id base on database.<p>
  6. * If there is host name & port in the environment, we considered that the node runs in Docker container<br>
  7. * Otherwise, the node runs on an actual machine.
  8. *
  9. * @return assigned worker id
  10. */
  11. @Transactional(rollbackFor = Exception.class)
  12. @Override
  13. public long assignWorkerId() {
  14. WorkNodeDO workNode = buildWorkerNode();
  15. workNodeService.insertWorkerNode(workNode);
  16. return workNode.getWorkNodeId();
  17. }
  18. /**
  19. * Build worker node entity by IP and PORT
  20. */
  21. private WorkNodeDO buildWorkerNode() {
  22. WorkNodeDO workNode = new WorkNodeDO();
  23. if (DockerUtils.isDocker()) {
  24. workNode.setType(WorkerNodeType.CONTAINER.value());
  25. workNode.setHostName(DockerUtils.getDockerHost());
  26. workNode.setPort(DockerUtils.getDockerPort());
  27. workNode.setLaunchDate(new Date());
  28. } else {
  29. workNode.setType(WorkerNodeType.ACTUAL.value());
  30. workNode.setHostName(NetUtils.getLocalAddress());
  31. workNode.setPort(System.currentTimeMillis() + "-" + new Random().nextInt(100000));
  32. workNode.setLaunchDate(new Date());
  33. }
  34. return workNode;
  35. }
  36. }
  37. @Configuration
  38. public class IdGeneratorConfiguration {
  39. @Bean
  40. public DisposableWorkerIdAssigner disposableWorkerIdAssigner() {
  41. return new DisposableWorkerIdAssigner();
  42. }
  43. @Bean
  44. public CachedUidGenerator cachedUidGenerator() {
  45. CachedUidGenerator cachedUidGenerator = new CachedUidGenerator();
  46. cachedUidGenerator.setWorkerIdAssigner(disposableWorkerIdAssigner());
  47. return cachedUidGenerator;
  48. }
  49. }

测试

  1. @RestController
  2. @RequestMapping("/v1/test")
  3. public class TestController {
  4. @Autowired
  5. private UidGenerator uidGenerator;
  6. @GetMapping("/uid")
  7. public Long index() {
  8. return uidGenerator.getUID();
  9. }
  10. }

测试成功

发表评论

表情:
评论列表 (有 0 条评论,109人围观)

还没有评论,来说两句吧...

相关阅读

    相关 生成全局唯一ID

    在实际业务处理中,有时需要生成全局唯一ID来区别同类型的不同事物,介绍一下几种方式及其C++实现 //获取全局唯一ID //server_id为服务的id,因