diff --git a/epmet-user/epmet-user-server/src/main/java/com/epmet/UserApplication.java b/epmet-user/epmet-user-server/src/main/java/com/epmet/UserApplication.java index caf839f79a..6f90b55f0a 100644 --- a/epmet-user/epmet-user-server/src/main/java/com/epmet/UserApplication.java +++ b/epmet-user/epmet-user-server/src/main/java/com/epmet/UserApplication.java @@ -8,6 +8,7 @@ package com.epmet; +import com.epmet.util.MySequence; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.web.servlet.ServletComponentScan; @@ -31,6 +32,7 @@ public class UserApplication { public static void main(String[] args) { SpringApplication.run(UserApplication.class, args); + MySequence identifierGenerator = new MySequence(); } } diff --git a/epmet-user/epmet-user-server/src/main/java/com/epmet/util/MySequence.java b/epmet-user/epmet-user-server/src/main/java/com/epmet/util/MySequence.java new file mode 100644 index 0000000000..28475b916f --- /dev/null +++ b/epmet-user/epmet-user-server/src/main/java/com/epmet/util/MySequence.java @@ -0,0 +1,214 @@ +/* + * Copyright (c) 2011-2021, baomidou (jobob@qq.com). + * + * 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.epmet.util; + +import com.alibaba.fastjson.JSON; +import com.baomidou.mybatisplus.core.toolkit.Assert; +import com.baomidou.mybatisplus.core.toolkit.StringPool; +import com.baomidou.mybatisplus.core.toolkit.StringUtils; +import com.baomidou.mybatisplus.core.toolkit.SystemClock; +import com.epmet.commons.tools.utils.HttpClientManager; +import lombok.extern.slf4j.Slf4j; +import org.apache.ibatis.logging.Log; +import org.apache.ibatis.logging.LogFactory; + +import java.lang.management.ManagementFactory; +import java.net.InetAddress; +import java.net.NetworkInterface; +import java.util.concurrent.ThreadLocalRandom; + +/** + * 分布式高效有序 ID 生产黑科技(sequence) + * + *

优化开源项目:https://gitee.com/yu120/sequence

+ * + * @author hubin + * @since 2016-08-18 + */ +@Slf4j +public class MySequence { + + private static final Log logger = LogFactory.getLog(MySequence.class); + /** + * 时间起始标记点,作为基准,一般取系统的最近时间(一旦确定不能变动) + */ + private final long twepoch = 1288834974657L; + /** + * 机器标识位数 + */ + private final long workerIdBits = 5L; + private final long datacenterIdBits = 5L; + private final long maxWorkerId = -1L ^ (-1L << workerIdBits); + private final long maxDatacenterId = -1L ^ (-1L << datacenterIdBits); + /** + * 毫秒内自增位 + */ + private final long sequenceBits = 12L; + private final long workerIdShift = sequenceBits; + private final long datacenterIdShift = sequenceBits + workerIdBits; + /** + * 时间戳左移动位 + */ + private final long timestampLeftShift = sequenceBits + workerIdBits + datacenterIdBits; + private final long sequenceMask = -1L ^ (-1L << sequenceBits); + + private final long workerId; + + /** + * 数据标识 ID 部分 + */ + private final long datacenterId; + /** + * 并发控制 + */ + private long sequence = 0L; + /** + * 上次生产 ID 时间戳 + */ + private long lastTimestamp = -1L; + + public MySequence() { + this.datacenterId = getDatacenterId(maxDatacenterId); + this.workerId = getMaxWorkerId(datacenterId, maxWorkerId); + String msg = "MySequence datacenterId:" + this.datacenterId + ";workerId:" + this.workerId; + log.info(msg); + HttpClientManager.getInstance().sendAlarmMsg(msg); + } + + /** + * 有参构造器 + * + * @param workerId 工作机器 ID + * @param datacenterId 序列号 + */ + public MySequence(long workerId, long datacenterId) { + Assert.isFalse(workerId > maxWorkerId || workerId < 0, + String.format("MySequence worker Id can't be greater than %d or less than 0", maxWorkerId)); + Assert.isFalse(datacenterId > maxDatacenterId || datacenterId < 0, + String.format("MySequence datacenter Id can't be greater than %d or less than 0", maxDatacenterId)); + this.workerId = workerId; + this.datacenterId = datacenterId; + } + + /** + * 获取 maxWorkerId + */ + protected static long getMaxWorkerId(long datacenterId, long maxWorkerId) { + StringBuilder mpid = new StringBuilder(); + mpid.append(datacenterId); + String name = ManagementFactory.getRuntimeMXBean().getName(); + String msg = "MySequence getMaxWorkerId name:" + name; + log.info(msg); + HttpClientManager.getInstance().sendAlarmMsg(msg); + if (StringUtils.isNotBlank(name)) { + /* + * GET jvmPid + */ + mpid.append(name.split(StringPool.AT)[0]); + } + /* + * MAC + PID 的 hashcode 获取16个低位 + */ + return (mpid.toString().hashCode() & 0xffff) % (maxWorkerId + 1); + } + + /** + * 数据标识id部分 + */ + protected static long getDatacenterId(long maxDatacenterId) { + long id = 0L; + try { + InetAddress ip = InetAddress.getLocalHost(); + NetworkInterface network = NetworkInterface.getByInetAddress(ip); + String msg = "MySequence ip:" + JSON.toJSONString(ip) + ";network: " + JSON.toJSONString(network); + log.info(msg); + HttpClientManager.getInstance().sendAlarmMsg(msg); + if (network == null) { + id = 1L; + log.info("MySequen cenetwork ==null "); + } else { + byte[] mac = network.getHardwareAddress(); + if (null != mac) { + id = ((0x000000FF & (long) mac[mac.length - 2]) | (0x0000FF00 & (((long) mac[mac.length - 1]) << 8))) >> 6; + id = id % (maxDatacenterId + 1); + } + } + } catch (Exception e) { + logger.warn(" getDatacenterId: " + e.getMessage()); + } + return id; + } + + /** + * 获取下一个 ID + * + * @return 下一个 ID + */ + public synchronized long nextId() { + long timestamp = timeGen(); + //闰秒 + if (timestamp < lastTimestamp) { + long offset = lastTimestamp - timestamp; + if (offset <= 5) { + try { + wait(offset << 1); + timestamp = timeGen(); + if (timestamp < lastTimestamp) { + throw new RuntimeException(String.format("Clock moved backwards. Refusing to generate id for %d milliseconds", offset)); + } + } catch (Exception e) { + throw new RuntimeException(e); + } + } else { + throw new RuntimeException(String.format("Clock moved backwards. Refusing to generate id for %d milliseconds", offset)); + } + } + + if (lastTimestamp == timestamp) { + // 相同毫秒内,序列号自增 + sequence = (sequence + 1) & sequenceMask; + if (sequence == 0) { + // 同一毫秒的序列数已经达到最大 + timestamp = tilNextMillis(lastTimestamp); + } + } else { + // 不同毫秒内,序列号置为 1 - 3 随机数 + sequence = ThreadLocalRandom.current().nextLong(1, 3); + } + + lastTimestamp = timestamp; + + // 时间戳部分 | 数据中心部分 | 机器标识部分 | 序列号部分 + return ((timestamp - twepoch) << timestampLeftShift) + | (datacenterId << datacenterIdShift) + | (workerId << workerIdShift) + | sequence; + } + + protected long tilNextMillis(long lastTimestamp) { + long timestamp = timeGen(); + while (timestamp <= lastTimestamp) { + timestamp = timeGen(); + } + return timestamp; + } + + protected long timeGen() { + return SystemClock.now(); + } + +} + diff --git a/epmet-user/epmet-user-server/src/test/java/com/epmet/epmetuser/test/UserControllerTest.java b/epmet-user/epmet-user-server/src/test/java/com/epmet/epmetuser/test/UserControllerTest.java index 06d674a4e3..751a7b7be1 100644 --- a/epmet-user/epmet-user-server/src/test/java/com/epmet/epmetuser/test/UserControllerTest.java +++ b/epmet-user/epmet-user-server/src/test/java/com/epmet/epmetuser/test/UserControllerTest.java @@ -1,7 +1,10 @@ package com.epmet.epmetuser.test; +import com.baomidou.mybatisplus.core.toolkit.IdWorker; import com.epmet.commons.tools.constant.AppClientConstant; +import com.epmet.dao.UserDao; import com.epmet.dto.result.LoginUserDetailsResultDTO; +import com.epmet.entity.UserEntity; import com.epmet.service.UserService; import org.junit.Test; import org.junit.runner.RunWith; @@ -15,11 +18,25 @@ public class UserControllerTest { @Autowired private UserService userService; + @Autowired + private UserDao userDao; @Test public void getLoginUserDetails() { LoginUserDetailsResultDTO loginUserDetails = userService.getLoginUserDetails(AppClientConstant.APP_GOV, AppClientConstant.CLIENT_WXMP, "4aaab913d9f11d90a2cb4dd21b075259"); System.out.println(loginUserDetails); } + @Test + public void insertUser() { + UserEntity entity = new UserEntity(); + + entity.setCustomerId("test_ljj"); + String idStr = IdWorker.getIdStr(); + System.out.println(idStr); + + + //int insert = userDao.insert(entity); + //System.out.println(insert); + } }