UidGenerator源码地址
UidGenerator官方中文文档
由于UidGenerator没有上传jar包到maven仓库上,需要从GitHub上上面下载源码,自己打成jar包在引入到项目中;
下载UidGenerator源码后需要修改源码pom文件中的mybatis,mybatis-spring,mysql-connector-java这三个jar包的版本,版本号和自己springboot工程里面对应三个jar包的版本号一致,不然会导致引入UidGenerator后mybatis启动报错。
<dependency>
<groupId>org.mybatisgroupId>
<artifactId>mybatisartifactId>
<version>3.5.1version>
dependency>
<dependency>
<groupId>org.mybatisgroupId>
<artifactId>mybatis-springartifactId>
<version>2.0.1version>
dependency>
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
<version>8.0.17version>
<scope>testscope>
dependency>
在自己的项目中引入UidGenerator的maven配置,groupId,artifactId,version在自己本地打包时都可以任意修改
<dependency>
<groupId>com.baidu.fsggroupId>
<artifactId>uid-generatorartifactId>
<version>1.0.0-RELEASESversion>
dependency>
这一步跟官方文档的步骤一步骤二一样,有一点要注意,官方文档的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;
由于UidGenerator依赖于MySQL的WORKER_NODE表来辅助生成uid,需要在自己的项目中增加WORKER_NODE相关的mybatis操作类;
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.
* If there is host name & port in the environment, we considered that the node runs in Docker container
* 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;
}
}
#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
初始化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
*
* 接入指引文档:https://blog.csdn.net/weixin_39338423/article/details/103972134
*
* 百度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进行填充补全
//
//另外一种RingBuffer填充时机, 在Schedule线程中, 周期性检查填充
//默认:不配置此项, 即不实用Schedule线程. 如需使用, 请指定Schedule线程时间间隔, 单位:秒
cachedUidGenerator.setScheduleInterval(60L);
//拒绝策略: 当环已满, 无法继续填充时
//默认无需指定, 将丢弃Put操作, 仅日志记录. 如有特殊需求, 请实现RejectedPutBufferHandler接口(支持Lambda表达式)
//
//cachedUidGenerator.setRejectedPutBufferHandler();
//拒绝策略: 当环已空, 无法继续获取时 -->
//默认无需指定, 将记录日志, 并抛出UidGenerateException异常. 如有特殊需求, 请实现RejectedTakeBufferHandler接口(支持Lambda表达式) -->
//
return cachedUidGenerator;
}
}
只需引入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);
}
}