第2-2-4章 常见组件与中台化-常用组件服务介绍-分布式ID-附Snowflake雪花算法的代码实现( 三 )

2.3.4 项目截图

  • 后端代码

第2-2-4章 常见组件与中台化-常用组件服务介绍-分布式ID-附Snowflake雪花算法的代码实现

文章插图
  • swagger页面

第2-2-4章 常见组件与中台化-常用组件服务介绍-分布式ID-附Snowflake雪花算法的代码实现

文章插图
2.3.5 Snowflake雪花算法的代码实现package com.itheima.distributedid.core;import com.itheima.distributedid.core.domain.DistributedIdException;import java.lang.management.ManagementFactory;import java.net.InetAddress;import java.net.NetworkInterface;/** * Twitter的Snowflake算法 * <p> * 协议格式   1:  41位时间戳      2:5位数据中心标识     3:5位机器标识   4:12位序列号 * <p> * 1111111111111111111111111111111   11111    11111    111111111111 */public class Snowflake {    //起始时间戳,可以修改为服务器第一次启动的时间    //一旦服务已经开始使用,起始时间戳就不能改变了 , 理论上可以使用69年    private final static long START_TIME = 1484754361114L;    /**     * 每一个部分占用的位数     */    private final static long SEQUENCE_BIT = 12;//序列号占用的位数    private final static long MACHINE_BIT = 5;//序机器标识 占用的位数    private final static long DATA_CENTER_BIT = 5;//数据中心标识占用的位数    /**     * 每一个部分的最大值  11111111111111111    1111111100000   000000000011111     */    private final static long MAX_DATA_CENTER_ID = ~(-1L << DATA_CENTER_BIT);    private final static long MAX_MACHINE_ID = ~(-1L << MACHINE_BIT);    private final static long MAX_SEQUENCE = ~(-1L << SEQUENCE_BIT);    /**     * 每一部分向左位移数 1111111111111111111111111111111   11111    11111    111111111111     */    private final static long MACHINE_LEFT = SEQUENCE_BIT;    private final static long DATA_CENTER_LEFT = SEQUENCE_BIT + MACHINE_BIT;    private final static long TIMESTAMP_LEFT = DATA_CENTER_LEFT + DATA_CENTER_BIT;    private long dataCenterId;//数据中心ID    private long machineId;//数据中心ID    private long sequence = 0L;//数据中心ID    private long lastTimestamp = -1L;//数据中心ID    /**     * 分布式部署的时候,数据节点标识和机器标识作为联合键,必须唯一的     *     * @param dataCenterId 数据中心标识ID     * @param machineId    机器标识ID     */    public Snowflake(long dataCenterId, long machineId) {        if (dataCenterId > MAX_DATA_CENTER_ID || dataCenterId < 0) {            throw new DistributedIdException("数据中心ID不合法");        }        if (machineId > MAX_MACHINE_ID || machineId < 0) {            throw new DistributedIdException("机器标识ID不合法");        }        this.dataCenterId = dataCenterId;        this.machineId = machineId;    }    /**     * 获取下一个ID     *     * @return     */    public synchronized long nextId() {        long currentTmestamp = getNowTimestamp();        if (currentTmestamp < lastTimestamp) {            throw new RuntimeException("时钟错误,拒绝生成ID");        }        if (currentTmestamp == lastTimestamp) {            //相同毫秒内,序列号自增            sequence = (sequence + 1) & MAX_SEQUENCE;            //同一毫秒的序列号已经达到最大            if (sequence == 0L) {                currentTmestamp = getNexMill();            }        } else {            //不同毫秒内 , 序列号置为0            sequence = 0L;        }        lastTimestamp = currentTmestamp;        return (currentTmestamp - START_TIME) << TIMESTAMP_LEFT  //时间戳的部分                | dataCenterId << DATA_CENTER_LEFT //数据中心的部分                | machineId << MACHINE_LEFT //机器标识的部分                | sequence;  //序列号的部分    }    /**     * 保证获取到的毫秒值是在最后一次分发ID的毫秒值之后lastTimestamp     * 当某一个毫秒,序列号用完了之后,等待到下一个毫秒,在进行序列号的使用     *     * @return     */    private long getNexMill() {        long timestamp = this.getNowTimestamp();        //不断的遍历,直到获取到lastTimestamp下一个毫秒值        while (timestamp <= lastTimestamp) {            //进行时间回拨            timestamp = this.getNowTimestamp();        }        return timestamp;    }    //获取当前毫秒值    private long getNowTimestamp() {        return System.currentTimeMillis();    }    /**     * 使用当前计算机的MAC生成数据中心标识ID     *     * @param maxDataCenterId     * @return     */    private static long getDataCenterId(long maxDataCenterId) {        long id = 0L;        try {            InetAddress ip = InetAddress.getLocalHost();            NetworkInterface network = NetworkInterface.getByInetAddress(ip);            if (network == null) {                id = 1L;            } else {                byte[] mac = network.getHardwareAddress();                if (mac != null) {                    id = ((0x000000FF & (long) mac[mac.length - 1]) | (0x0000FF00 & (((long) mac[mac.length - 2])                            << 8))) >> 6;                    id = id % (maxDataCenterId + 1);                }            }        } catch (Exception e) {            e.printStackTrace();        }        return id;    }    //根据当前计算机的进程PID生成机器识别ID    private static long getMachineId(long dataCenterId, long maxMachineId) {        StringBuilder sb = new StringBuilder();        sb.append(dataCenterId);        //获取JVM进程的PID        String name = ManagementFactory.getRuntimeMXBean().getName();        if (name != null) {            sb.append(name.split("@")[0]);        }        /**         * MAC+PID 的hashcode 获取16个低位         */        int id = sb.toString().hashCode() & 0xffff;        return id % (maxMachineId + 1);    }    public Snowflake() {        dataCenterId = getDataCenterId(MAX_DATA_CENTER_ID);        machineId = getMachineId(dataCenterId, MAX_MACHINE_ID);    }    //public static void main(String[] args) {    //    //指定数据中心和机器识别id    //    Snowflake snowflake = new Snowflake(2, 3);    //    System.out.println("指定数据中心和机器识别ID来生成ID");    //    for (int i = 0; i < 10; i++) {    //        System.out.println(snowflake.nextId());    //    }    //    //    //默认快速使用方式    //    snowflake = new Snowflake();    //    System.out.println("快速使用方式来生成ID");    //    for (int i = 0; i < 10; i++) {    //        System.out.println(snowflake.nextId());    //    }    //}}

推荐阅读