1. 背景
有N种方式生成分布式ID的bean,由调用方决定采用哪种方式,下边这个demo就可以做个demo
2. 代码
/**
* 生成ID接口
*/
public interface IIdGenerator {
/**
* 获取ID,目前有两种实现方式
* 1. 雪花算法,用于生成单号
* 2. 日期算法,用于生成活动编号类,特性是生成数字串较短,但指定时间内不能生成太多
* 3. 随机算法,用于生成策略ID
*/
long nextId();
}
/**
* 工具类生成 org.apache.commons.lang3.RandomStringUtils
*/
@Component
public class RandomNumeric implements IIdGenerator {
@Override
public long nextId() {
return Long.parseLong(RandomStringUtils.randomNumeric(11));
}
}
/**
* 短码生成策略,仅支持很小的调用量,用于生成活动配置类编号,保证全局唯一
*/
@Component
public class ShortCode implements IIdGenerator {
@Override
public synchronized long nextId() {
Calendar calendar = Calendar.getInstance();
int year = calendar.get(Calendar.YEAR);
int week = calendar.get(Calendar.WEEK_OF_YEAR);
int day = calendar.get(Calendar.DAY_OF_WEEK);
int hour = calendar.get(Calendar.HOUR_OF_DAY);
// 打乱排序:2020年为准 + 小时 + 周期 + 日 + 三位随机数
StringBuilder idStr = new StringBuilder();
idStr.append(year - 2020);
idStr.append(hour);
idStr.append(String.format("%02d", week));
idStr.append(day);
idStr.append(String.format("%03d", new Random().nextInt(1000)));
return Long.parseLong(idStr.toString());
}
}
/**
* hutool 工具包下的雪花算法
*/
@Component
public class SnowFlake implements IIdGenerator {
private Snowflake snowflake;
@PostConstruct
public void init() {
// 0 ~ 31 位,可以采用配置的方式使用
long workerId;
try {
workerId = NetUtil.ipv4ToLong(NetUtil.getLocalhostStr());
} catch (Exception e) {
workerId = NetUtil.getLocalhostStr().hashCode();
}
workerId = workerId >> 16 & 31;
long dataCenterId = 1L;
snowflake = IdUtil.createSnowflake(workerId, dataCenterId);
}
@Override
public synchronized long nextId() {
return snowflake.nextId();
}
}
@Configuration
public class IdContext {
/**
* 创建 ID 生成策略对象,属于策略设计模式的使用方式
*
*/
@Bean
public Map<Constants.Ids, IIdGenerator> idGeneratorMap(SnowFlake snowFlake, ShortCode shortCode, RandomNumeric randomNumeric) {
Map<Constants.Ids, IIdGenerator> idGeneratorMap = new HashMap<>(8);
idGeneratorMap.put(Constants.Ids.SnowFlake, snowFlake);
idGeneratorMap.put(Constants.Ids.ShortCode, shortCode);
idGeneratorMap.put(Constants.Ids.RandomNumeric, randomNumeric);
return idGeneratorMap;
}
}
@RunWith(SpringRunner.class)
@SpringBootTest
public class SupportTest {
private Logger logger = LoggerFactory.getLogger(SupportTest.class);
@Resource
private Map<Constants.Ids, IIdGenerator> idGeneratorMap;
@Test
public void test_ids() {
logger.info("雪花算法策略,生成ID:{}", idGeneratorMap.get(Constants.Ids.SnowFlake).nextId());
logger.info("日期算法策略,生成ID:{}", idGeneratorMap.get(Constants.Ids.ShortCode).nextId());
logger.info("随机算法策略,生成ID:{}", idGeneratorMap.get(Constants.Ids.RandomNumeric).nextId());
}
}
3. 总结
1.策略模式有N种写法,对于map的注入,spring5已经默认实现了,可以省去idGeneratorMap这个map