springboot2接入百度UidGenerator

官方文档

UidGenerator源码地址
UidGenerator官方中文文档

接入步骤

1.下载源码并打包

由于UidGenerator没有上传jar包到maven仓库上,需要从GitHub上上面下载源码,自己打成jar包在引入到项目中;
下载UidGenerator源码后需要修改源码pom文件中的mybatis,mybatis-spring,mysql-connector-java这三个jar包的版本,版本号和自己springboot工程里面对应三个jar包的版本号一致,不然会导致引入UidGenerator后mybatis启动报错。

<!-- MyBatis -->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.5.1</version>
        </dependency>
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis-spring</artifactId>
            <version>2.0.1</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.17</version>
            <scope>test</scope>
        </dependency>

2.springboot工程pom文件引入UidGenerator配置

在自己的项目中引入UidGenerator的maven配置,groupId,artifactId,version在自己本地打包时都可以任意修改

			<!-- 百度uidgenerator 唯一ID生成器
                 这个jar包maven仓库里面没有上传,需要自己把源码拉下来本地打包
                 源码地址:https://github.com/baidu/uid-generator -->
            <dependency>
                <groupId>com.baidu.fsg</groupId>
                <artifactId>uid-generator</artifactId>
                <version>1.0.0-RELEASES</version>
            </dependency>

3.本地数据库创建UidGenerator依赖的表结构

这一步跟官方文档的步骤一步骤二一样,有一点要注意,官方文档的MODIFIED,CREATED两个字段的类型都是TIMESTAMP,MySQL5.6以上的版本建表时可能会报:Error Code: 1067. Invalid default value for ‘CREATED’ 的错误,只要把字段类型修改为datetime 即可。SQL如下:

CREATE TABLE WORKER_NODE
(
ID BIGINT NOT NULL AUTO_INCREMENT COMMENT 'auto increment id',
HOST_NAME VARCHAR(64) NOT NULL COMMENT 'host name',
PORT VARCHAR(64) NOT NULL COMMENT 'port',
TYPE INT NOT NULL COMMENT 'node type: ACTUAL or CONTAINER',
LAUNCH_DATE DATE NOT NULL COMMENT 'launch date',
MODIFIED datetime NOT NULL COMMENT 'modified time',
CREATED datetime NOT NULL COMMENT 'created time',
PRIMARY KEY(ID)
)
 COMMENT='DB WorkerID Assigner for UID Generator',ENGINE = INNODB;

4.拷贝UidGenerator数据库操作相关文件

由于UidGenerator依赖于MySQL的WORKER_NODE表来辅助生成uid,需要在自己的项目中增加WORKER_NODE相关的mybatis操作类;

  1. 把WorkerNodeDAO拷贝到自己目录下,改名为WorkerNodeMapper;
  2. 把WORKER_NODE.xml文件拷贝到resource的目录下,改名为WorkerNodeMapper.xml,并把里面的namespace="com.baidu.fsg.uid.worker.dao.WorkerNodeDAO"改为自己项目中的WorkerNodeMapper;

在这里插入图片描述
3. 拷贝DisposableWorkerIdAssigner类到自己的工程中,并把里面依赖的WorkerNodeDAO 改为本地新增的WorkerNodeMapper;
在这里插入图片描述

/*
 * Copyright (c) 2017 Baidu, Inc. All Rights Reserve.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.wangzhongxing.springcloud.dao.uidgenerator;

import com.baidu.fsg.uid.utils.DockerUtils;
import com.baidu.fsg.uid.utils.NetUtils;
import com.baidu.fsg.uid.worker.WorkerIdAssigner;
import com.baidu.fsg.uid.worker.WorkerNodeType;
import com.baidu.fsg.uid.worker.entity.WorkerNodeEntity;
import com.wangzhongxing.springcloud.dao.mapper.WorkerNodeMapper;
import org.apache.commons.lang.math.RandomUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;

/**
 * Represents an implementation of {@link WorkerIdAssigner},
 * the worker id will be discarded after assigned to the UidGenerator
 *
 * @author yutianbao
 */
@Component("disposableWorkerIdAssigner")
public class DisposableWorkerIdAssigner implements WorkerIdAssigner {

    private static final Logger LOGGER = LoggerFactory.getLogger(DisposableWorkerIdAssigner.class);

    @Resource
    private WorkerNodeMapper workerNodeMapper;

    /**
     * Assign worker id base on database.<p>
     * If there is host name & port in the environment, we considered that the node runs in Docker container<br>
     * Otherwise, the node runs on an actual machine.
     *
     * @return assigned worker id
     */
    @Transactional
    public long assignWorkerId() {
        // build worker node entity
        WorkerNodeEntity workerNodeEntity = buildWorkerNode();

        // add worker node for new (ignore the same IP + PORT)
        workerNodeMapper.addWorkerNode(workerNodeEntity);
        LOGGER.info("Add worker node:" + workerNodeEntity);

        return workerNodeEntity.getId();
    }

    /**
     * Build worker node entity by IP and PORT
     */
    private WorkerNodeEntity buildWorkerNode() {
        WorkerNodeEntity workerNodeEntity = new WorkerNodeEntity();
        if (DockerUtils.isDocker()) {
            workerNodeEntity.setType(WorkerNodeType.CONTAINER.value());
            workerNodeEntity.setHostName(DockerUtils.getDockerHost());
            workerNodeEntity.setPort(DockerUtils.getDockerPort());

        } else {
            workerNodeEntity.setType(WorkerNodeType.ACTUAL.value());
            workerNodeEntity.setHostName(NetUtils.getLocalAddress());
            workerNodeEntity.setPort(System.currentTimeMillis() + "-" + RandomUtils.nextInt(100000));
        }

        return workerNodeEntity;
    }

}

  1. 修改@MapperScan注解,添加com.baidu.fsg.uid包,例如:@MapperScan(basePackages = {“com.wangzhongxing.springcloud.dao.mapper”, “com.baidu.fsg.uid”})
  2. 修改mybatis.mapper-locations配置,增加WorkerNodeMapper.xml所在的路径,我是放到了mybatis/mapping/custom/目录下:
#mybatis配置
mybatis:
# 指定全局配置文件位置
  config-location: classpath:mybatis/mybatis-config.xml
  # 指定sql映射文件位置
  mapper-locations: classpath:mybatis/mapping/auto/*.xml,classpath:mybatis/mapping/custom/*.xml
  type-aliases-package: com.wangzhongxing.springcloud.dao.dataobject

5.添加UidGenerator相关bean配置

初始化DisposableWorkerIdAssigner,CachedUidGenerator 这两个bean,初始化配置如下:

package com.wangzhongxing.springcloud.dao.uidgenerator;

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

/**
 * @Auther: wangzhongxing
 * @Date: 2020/1/13 17:52
 * @Description: https://github.com/baidu/uid-generator/blob/master/README.zh_cn.md
 * <p>
 * 接入指引文档:https://blog.csdn.net/weixin_39338423/article/details/103972134
 * <p>
 * 百度id生成器
 * 两种生成器: DefaultUidGenerator、CachedUidGenerator。如对UID生成性能有要求, 请使用CachedUidGenerator
 * 对应Spring配置分别为: default-uid-spring.xml、cached-uid-spring.xml
 */
@Configuration
public class CachedUidGeneratorConfig {

    /**
     * disposableWorkerIdAssigner的入参对象类型最好使用 WorkerIdAssigner,
     * 否则其他地方引入CGLib动态代理的时候可能会导致代理混用的问题
     *
     * @param disposableWorkerIdAssigner
     * @return
     */
    @Bean
    public DefaultUidGenerator defaultUidGenerator(WorkerIdAssigner disposableWorkerIdAssigner) {
        DefaultUidGenerator defaultUidGenerator = new DefaultUidGenerator();
        defaultUidGenerator.setWorkerIdAssigner(disposableWorkerIdAssigner);
        /**
         * 关于UID比特分配的建议:
         * 对于并发数要求不高、期望长期使用的应用, 可增加timeBits位数, 减少seqBits位数.
         * 例如节点采取用完即弃的WorkerIdAssigner策略, 重启频率为12次/天, 那么配置成:
         * {"workerBits":23,"timeBits":31,"seqBits":9}时, 可支持28个节点以整体并发量14400 UID/s的速度持续运行68年.
         *
         * 对于节点重启频率频繁、期望长期使用的应用, 可增加workerBits和timeBits位数, 减少seqBits位数.
         * 例如节点采取用完即弃的WorkerIdAssigner策略, 重启频率为24*12次/天, 那么配置成:
         * {"workerBits":27,"timeBits":30,"seqBits":6}时, 可支持37个节点以整体并发量2400 UID/s的速度持续运行34年.
         */
        // 以下为可选配置, 如未指定将采用默认值
        // timeBits,相对于时间基点"2016-05-20"的增量值,单位:秒,可使用的时间为2^timeBis 秒
        // 例如:timeBits=30,则可使用2^30秒,约34年,timeBits=31,则可使用2^31秒,约68年
        defaultUidGenerator.setTimeBits(32);
        // 机器id,最多可支持2^22约420w次机器启动。内置实现为在启动时由数据库分配,默认分配策略为用后即弃,
        // 每次启动都会重新生成一批ID,因此重启次数也是会有限制的,后续可提供复用策略。
        defaultUidGenerator.setWorkerBits(22);
        // 每秒下的并发序列,9 bits可支持每台服务器每秒512个并发。
        defaultUidGenerator.setSeqBits(9);
        defaultUidGenerator.setEpochStr("2020-01-01");

        return defaultUidGenerator;
    }

    /**
     * disposableWorkerIdAssigner的入参对象类型最好使用 WorkerIdAssigner,
     * 否则其他地方引入CGLib动态代理的时候可能会导致代理混用的问题
     *
     * @param disposableWorkerIdAssigner
     * @return
     */
    @Bean
    public CachedUidGenerator cachedUidGenerator(WorkerIdAssigner disposableWorkerIdAssigner) {
        CachedUidGenerator cachedUidGenerator = new CachedUidGenerator();
        cachedUidGenerator.setWorkerIdAssigner(disposableWorkerIdAssigner);
        /**
         * 关于UID比特分配的建议:
         * 对于并发数要求不高、期望长期使用的应用, 可增加timeBits位数, 减少seqBits位数.
         * 例如节点采取用完即弃的WorkerIdAssigner策略, 重启频率为12次/天, 那么配置成:
         * {"workerBits":23,"timeBits":31,"seqBits":9}时, 可支持28个节点以整体并发量14400 UID/s的速度持续运行68年.
         *
         * 对于节点重启频率频繁、期望长期使用的应用, 可增加workerBits和timeBits位数, 减少seqBits位数.
         * 例如节点采取用完即弃的WorkerIdAssigner策略, 重启频率为24*12次/天, 那么配置成:
         * {"workerBits":27,"timeBits":30,"seqBits":6}时, 可支持37个节点以整体并发量2400 UID/s的速度持续运行34年.
         */
        // 以下为可选配置, 如未指定将采用默认值
        // timeBits,相对于时间基点"2016-05-20"的增量值,单位:秒,可使用的时间为2^timeBis 秒
        // 例如:timeBits=30,则可使用2^30秒,约34年,timeBits=31,则可使用2^31秒,约68年
        cachedUidGenerator.setTimeBits(32);
        // 机器id,最多可支持2^22约420w次机器启动。内置实现为在启动时由数据库分配,默认分配策略为用后即弃,
        // 每次启动都会重新生成一批ID,因此重启次数也是会有限制的,后续可提供复用策略。
        cachedUidGenerator.setWorkerBits(22);
        // 每秒下的并发序列,9 bits可支持每台服务器每秒512个并发。
        cachedUidGenerator.setSeqBits(9);
        cachedUidGenerator.setEpochStr("2020-01-01");

        //RingBuffer size扩容参数, 可提高UID生成的吞吐量
        //默认:3, 原bufferSize=8192, 扩容后bufferSize= 8192 << 3 = 65536
        cachedUidGenerator.setBoostPower(3);
        // 指定何时向RingBuffer中填充UID, 取值为百分比(0, 100), 默认为50
        // 举例: bufferSize=1024, paddingFactor=50 -> threshold=1024 * 50 / 100 = 512.
        // 当环上可用UID数量 < 512时, 将自动对RingBuffer进行填充补全
        //<property name="paddingFactor" value="50"></property>

        //另外一种RingBuffer填充时机, 在Schedule线程中, 周期性检查填充
        //默认:不配置此项, 即不实用Schedule线程. 如需使用, 请指定Schedule线程时间间隔, 单位:秒
        cachedUidGenerator.setScheduleInterval(60L);

        //拒绝策略: 当环已满, 无法继续填充时
        //默认无需指定, 将丢弃Put操作, 仅日志记录. 如有特殊需求, 请实现RejectedPutBufferHandler接口(支持Lambda表达式)
        //<property name="rejectedPutBufferHandler" ref="XxxxYourPutRejectPolicy"></property>
        //cachedUidGenerator.setRejectedPutBufferHandler();
        //拒绝策略: 当环已空, 无法继续获取时 -->
        //默认无需指定, 将记录日志, 并抛出UidGenerateException异常. 如有特殊需求, 请实现RejectedTakeBufferHandler接口(支持Lambda表达式) -->
        //<property name="rejectedTakeBufferHandler" ref="XxxxYourTakeRejectPolicy"></property>

        return cachedUidGenerator;
    }
}

6.使用CachedUidGenerator 生成uid

只需引入cachedUidGenerator bean实例,直接调用cachedUidGenerator.getUID()方法即可生成uid

package com.wangzhongxing.springcloud;

import com.baidu.fsg.uid.UidGenerator;
import com.wangzhongxing.springcloud.web.SpringcloudTemplateWebApplication;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

/**
 * @Auther: wangzhongxing
 * @Date: 2020/1/14 14:57
 * @Description:
 */
@RunWith(SpringRunner.class)
@SpringBootTest(classes = SpringcloudTemplateWebApplication.class)
public class CachedUidGeneratorTest {

    @Autowired
    private UidGenerator cachedUidGenerator;

    @Test
    public void getUidTest() {
        Long uid = cachedUidGenerator.getUID();

        System.out.println(uid);
    }

}

每生成一个uid都会往WORKER_NODE表中插入一条记录
在这里插入图片描述

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值