-- moudle tag
local tag = KEYS[1];
if tag == nil then
tag = 'default';
end
-- if user do not pass shardId, default partition is 0.
local partition
if KEYS[2] == nil then
partition = 0;
else
partition = KEYS[2] % 4096;
endlocal seqKey = 'idgenerator_' .. tag .. '_' .. partition;
local step = 1;local count;
repeat
count = tonumber(redis.call('INCRBY', seqKey, step));
until count < (1024 - step)-- count how many seq are generated in one millisecond
if count == step then
redis.call('PEXPIRE', seqKey, 1);
endlocal now = redis.call('TIME');
-- second, microSecond, partition, seq
return { tonumber(now[1]), tonumber(now[2]), partition, count }
-- moudle tag
local tag = KEYS[1];
if tag == nil then
tag = 'default';
end
-- if user do not pass shardId, default partition is 0.
local partition
if KEYS[2] == nil then
partition = 0;
else
partition = KEYS[2] % 4096;
endlocal seqKey = 'idgenerator_' .. tag .. '_' .. partition;
local step = 1;local count;
repeat
count = tonumber(redis.call('INCRBY', seqKey, step));
until count < (1024 - step)-- count how many seq are generated in one millisecond
if count == step then
redis.call('PEXPIRE', seqKey, 1);
endlocal now = redis.call('TIME');
-- second, microSecond, partition, seq
return { tonumber(now[1]), tonumber(now[2]), partition, count }
編寫 Service 以及實現
package org.idgenerator.service;/**
* 序列號生成器 Service
*/
public interface IdGenService {
String next();
}
package org.idgenerator.service.impl;import org.idgenerator.service.IdGenService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.script.RedisScript;
import org.springframework.scripting.support.ResourceScriptSource;
import org.springframework.stereotype.Service;import java.util.ArrayList;
import java.util.List;@Service
public class RedisIdGenService implements IdGenService { private Logger logger = LoggerFactory.getLogger(RedisIdGenService.class); private StringRedisTemplate stringRedisTemplate; private RedisScript<List> redisScript; public RedisIdGenService(StringRedisTemplate stringRedisTemplate) {
this.stringRedisTemplate = stringRedisTemplate;
Resource luaResource = new ResourceScriptSource(new ClassPathResource("redis-script-single.lua")).getResource();
RedisScript<List> redisScript = RedisScript.of(luaResource,List.class);
this.redisScript = redisScript;
} public String next() {
List<String> keys = new ArrayList<>();
//keys.add("USER_MOUDLE");
//keys.add("1");
List<Long> result = stringRedisTemplate.execute(redisScript, keys);
long id = buildId(result.get(0), result.get(1), result.get(2), result.get(3));
logger.info("序列號:" + id);
return String.valueOf(id);
} public long buildId(long second, long microSecond, long shardId, long seq) {
long miliSecond = second * 1000L + microSecond / 1000L;
return (miliSecond << 22) + (shardId << 10) + seq;
}
}
定義 IdGenAutoConfiguration 自動配置類
package org.idgenerator.autoconfigure;import org.idgenerator.service.IdGenService;
import org.idgenerator.service.impl.RedisIdGenService;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.core.StringRedisTemplate;@Configuration
@ConditionalOnClass({StringRedisTemplate.class})
public class IdGenAutoConfiguration { @Bean
@ConditionalOnMissingBean(IdGenService.class)
public IdGenService idGen(StringRedisTemplate stringRedisTemplate) {
return new RedisIdGenService(stringRedisTemplate);
}
}