推特雪花算法,基于hutool包

文章展示了如何在Java环境中使用Hutool的Snowflake类结合Redisson来实现分布式ID的生成。代码中定义了一个静态的Snowflake实例,通过Spring注解注入Redisson客户端,自定义工作ID以确保应用间ID不重复。在V2版本中,采用IP地址和主机名来动态计算工作ID和数据中心ID,同时提供了异常情况下的随机数备用方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

hutool包的Snowflake类
分布式的 SNOWFLAKE_WORKID
单例的Snowflake



import cn.hutool.core.lang.Snowflake;
import cn.hutool.core.util.IdUtil;
import org.redisson.api.RScript;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;

import java.util.Collections;


@Component
public class IdUtils {

    @Autowired
    private RedissonClient redissonClient;

    private final String applicationName;

    public IdUtils(@Value("${spring.application.name}") String applicationName) {
        this.applicationName = applicationName;
    }

    private static Snowflake SNOWFLAKE = null;


    public static Long getNextId() {
        return SNOWFLAKE.nextId();
    }

    /**
     * 自定义workerId,保证该应用的ID不会重复
     *
     * @return 新的id生成器
     */
    @Bean
    public void defaultSnowflake() {
        String workerName = applicationName + "-order-worker-id";
        Long SNOWFLAKE_WORKID = this.getWorkerId(workerName);
        SNOWFLAKE = IdUtil.getSnowflake(SNOWFLAKE_WORKID, 1);
    }

    /**
     * 容器环境生成workid 并redis缓存
     *
     * @param key
     * @return
     */
    public Long getWorkerId(String key) {
        String luaScript = "local isExist = redis.call('exists', KEYS[1])\n" +
                "if isExist == 1\n" +
                "then\n" +
                "    local workerId = redis.call('get', KEYS[1])\n" +
                "    workerId = (workerId + 1) % 31\n" +
                "    redis.call('set', KEYS[1], workerId)\n" +
                "    return workerId\n" +
                "else\n" +
                "    redis.call('set', KEYS[1], 0)\n" +
                "    return 0\n" +
                "end";

        RScript rScript = redissonClient.getScript();

        Long result = rScript.eval(RScript.Mode.READ_WRITE, luaScript, RScript.ReturnType.INTEGER, Collections.singletonList(key));
        return result;
    }
}


v2版本


import cn.hutool.core.lang.Snowflake;
import cn.hutool.core.util.IdUtil;
import org.apache.commons.lang3.RandomUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.SystemUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;

import java.net.Inet4Address;
import java.net.InetAddress;
import java.net.UnknownHostException;

@Component
public class SnowFlakeUtilV2 {

    private static Snowflake SNOWFLAKE = null;

    private static final Logger LOGGER = LoggerFactory.getLogger(SnowFlakeUtil.class);

    public static Long getNextId() {
        return SNOWFLAKE.nextId();
    }

    @Bean
    public void  getSnowflakeId(){
        //方式二:根据IP和hostName获取workId和dataCenterId
        long workId = this.getWorkId();
        long dataCenterId = this.getDataCenterId();
        SNOWFLAKE = IdUtil.getSnowflake(workId, dataCenterId);
    }

    /**
     * 根据IP Address 生成workId
     *
     * @return
     */
    private long getWorkId() {
        try {
            String hostAddress = Inet4Address.getLocalHost().getHostAddress();
            LOGGER.info("hostAddress========={}", hostAddress);
            int[] ints = StringUtils.toCodePoints(hostAddress);
            int sums = 0;
            for (int b : ints) {
                sums += b;
            }
            return (long) (sums % 32);
        } catch (UnknownHostException e) {
            LOGGER.error("根据IP获取workId失败。", e);
            // 如果获取失败,则使用随机数备用
            return RandomUtils.nextLong(0, 31);
        }
    }
    /**
     * 根据HostName 生成dataCenterId
     * @return
     */
    private long getDataCenterId() {
        String hostName = getHostName();
        LOGGER.info("hostName========={}", hostName);
        int[] ints = StringUtils.toCodePoints(hostName);
        int sums = 0;
        for (int i : ints) {
            sums += i;
        }
        return (long) (sums % 32);
    }

    /**
     * 获取 hostName
     *   SystemUtils.getHostName() 在mac系统为空处理
     * @return
     */
    public static String getHostName() {
        //获取当前操作系统名称,例如:windows xp,linux 等
        String osName = System.getProperty("os.name");
        String hostName = null;
        if(!StringUtils.startsWithIgnoreCase(osName,"mac")){
            hostName = SystemUtils.getHostName();
        }else{
            try {
                hostName = InetAddress.getLocalHost().getHostName().toUpperCase();
            } catch (UnknownHostException e) {
                hostName = "N/A";
                LOGGER.error("获取 hostName错误:", e);
            }
        }
        return hostName;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值