forked from rongchao/epmet-cloud-rizhao
				
			
				 10 changed files with 274 additions and 18 deletions
			
			
		@ -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) | 
				
			||||
 | 
					 * | 
				
			||||
 | 
					 * <p>优化开源项目:https://gitee.com/yu120/sequence</p>
 | 
				
			||||
 | 
					 * | 
				
			||||
 | 
					 * @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(); | 
				
			||||
 | 
					    } | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					} | 
				
			||||
 | 
					
 | 
				
			||||
					Loading…
					
					
				
		Reference in new issue