基于在eureka上注册的信息,instanceId在eureka上是唯一的,是有ip+port组成的。
@Value("${spring.cloud.client.ipAddress}")
private String clientAddress;
@Value("${server.port}")
private String serverPort;
我们创建了一个表来记录这些信息
CREATE TABLE `t_medical_instance` (
`id` int(4) NOT NULL AUTO_INCREMENT COMMENT '主键',
`instance_id` varchar(100) NOT NULL COMMENT '服务标示',
`del_flag` tinyint(1) DEFAULT NULL COMMENT '删除标示',
`update_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间',
`create_time` timestamp NULL DEFAULT NULL COMMENT '创建时间',
PRIMARY KEY (`id`),
UNIQUE KEY `service_id_UNIQUE` (`instance_id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COMMENT='节点信息保存';
每次读取表信息
MedicalInstance medicalInstance = medicalInstanceService.selectMedicalInstanceByInstance(instanceId);
if (medicalInstance == null) {
medicalInstance = new MedicalInstance();
medicalInstance.setInstanceId(instanceId);
medicalInstanceService.addData(medicalInstance);
}
if (medicalInstance.getId() > maxWorkerId) {
logger.info("workId不能大于最大机器码");
throw new IllegalArgumentException(String.format("worker Id can't be greater than %d or less than 0", maxWorkerId));
}
this.workerId = medicalInstance.getId();
medicalSnowFlake = this;
} catch (BizException e) {
logger.error("获取id失败,展示不能生成id",e);
throw new IllegalArgumentException("id生成初始化失败");
}
完整代码如下
/**
*@Author GUOSHAOHUA093
*@Description snowFlakeid生成类
*@Date 14:15 2019/1/11
*/
@Component
public class MedicalSnowFlake {
static Logger logger = LoggerFactory.getLogger(MedicalSnowFlake.class);
//其实时间戳 2017-01-01 00:00:00
private final static long twepoch = 1288834974657L;
//10bit(位)的工作机器id 中IP标识所占的位数 5bit(位)
private final static long workerIdBits = 5L;
//wordId标识最大值 31 即2的5次方减一。
private final static long maxWorkerId = ~(-1L << workerIdBits);
//10bit(位)的工作机器id 中数字标识id所占的位数 5bit(位)
private final static long dataCenterIdBits = 5L;
//数字标识id最大值 31 即2的5次方减一。
private final static long maxDatacenterId = ~(-1L << dataCenterIdBits);
//序列在id中占的位数 12bit
private final static long sequenceBits = 12L;
//序列最大值 4095 即2的12次方减一。
private final static long sequenceMax = ~(-1L << sequenceBits);
// 64位的数字:首位0 随后41位表示时间戳 随后10位工作机器id(5位IP标识 + 5位数字标识) 最后12位序列号
private final static long workerIdShift = sequenceBits;
private final static long datacenterIdShift = sequenceBits + workerIdBits;
private final static long timeLeftShift = sequenceBits + workerIdBits + dataCenterIdBits;
//机器码
private long workerId;
// 数据中心ID(0~3)
private long datacenterId = 0;
// 毫秒内序列(0~4095)
private long sequence = 0L;
// 上次生成ID的时间截
private long lastTime = -1L;
private static MedicalSnowFlake medicalSnowFlake;
@Value("${spring.application.name}")
private String applicationName;
@Value("${spring.cloud.client.ipAddress}")
private String clientAddress;
@Value("${server.port}")
private String serverPort;
@Autowired
@Qualifier("medicalInstanceService")
private IMedicalInstanceBiz medicalInstanceService;
@PostConstruct
public void init() {
try {
//用instanceId来指定workerId
String instanceId = clientAddress + ":" + serverPort;
MedicalInstance medicalInstance = medicalInstanceService.selectMedicalInstanceByInstance(instanceId);
if (medicalInstance == null) {
medicalInstance = new MedicalInstance();
medicalInstance.setInstanceId(instanceId);
medicalInstanceService.addData(medicalInstance);
}
if (medicalInstance.getId() > maxWorkerId) {
logger.info("workId不能大于最大机器码");
throw new IllegalArgumentException(String.format("worker Id can't be greater than %d or less than 0", maxWorkerId));
}
this.workerId = medicalInstance.getId();
medicalSnowFlake = this;
} catch (BizException e) {
logger.error("获取id失败,展示不能生成id",e);
throw new IllegalArgumentException("id生成初始化失败");
}
}
public static MedicalSnowFlake getInstance() {
return medicalSnowFlake;
}
public synchronized long nextId() {
//获取当前时间
long nowTime = currentTimeMillis();
//如果当前时间小于最后一次时间
if (nowTime < lastTime) {
logger.info("当前时间前于上次操作时间,当前时间有误: " + nowTime);
throw new RuntimeException(String.format("Clock moved backwards. Refusing to generate id for %d milliseconds", lastTime - nowTime));
}
if (nowTime == lastTime) {
sequence = (sequence + 1) & sequenceMax;
if (sequence == 0) {
nowTime = getNextTimeStamp();
}
} else {
sequence = 0L;
}
lastTime = nowTime;
return ((nowTime - twepoch) << timeLeftShift)
| (workerId << workerIdShift)
| (datacenterId << datacenterIdShift)
| sequence;
}
private long getNextTimeStamp() {
long nowTime;
do {
nowTime = System.currentTimeMillis();
} while (nowTime <= lastTime);
return nowTime;
}
protected long currentTimeMillis() {
return System.currentTimeMillis();
}
}