什么是Redisson?
俗話說他就是看門狗,看門狗機制是一種用于保持Redis連接活躍性的方法,通常用于分布式鎖的場景。看門狗的工作原理是:當客戶端獲取到鎖之后,會對Redis中的一個特定的鍵設置一個有限的過期時間,然后每隔一段時間(默認是15秒),客戶端會對這個鍵“續約”,即重新設置它的過期時間,以此來保持鎖的持有狀態,防止鎖因為某些原因(如客戶端崩潰或網絡問題)而被釋放。
以下是核心實戰部分
配置文件讀取
@ConfigurationProperties(prefix = "spring.redis.redisson"
)
@Data
public class RedissonProperties {/*** key前綴*/private String keyPrefix;/*** 拿鎖等待時間(毫秒)*/private long waitTime = 10000;/*** 默認ttl時間(毫秒)*/private long leaseTime = 60000;@Value("${spring.redis.redisson.config.clusterServersConfig.nodeAddresses}")private String nodeAddresses;@Value("${spring.redis.redisson.config.clusterServersConfig.scanInterval}")private Integer scanInterval;@Value("${spring.redis.redisson.config.threads}")private Integer threads;@Value("${spring.redis.redisson.config.nettyThreads}")private Integer nettyThreads;@Value("${spring.redis.redisson.config.transportMode}")private String transportMode;
}
yml文件
spring:##redis集群配置redis:database: 0timeout: 5000msredisson:config:clusterServersConfig:nodeAddresses: redis://10.xxx.xx.x1:6379,redis://10.xxx.xx.x2:6379,redis://10.xxx.xx.x3:6379scanInterval: 1000nettyThreads: 0threads: 0transportMode: NIOkey-prefix: test:keylease-time: 80000wait-time: 50000
redisson自動配置類
@Configuration
@ConditionalOnClass({Redisson.class})
@EnableConfigurationProperties({RedissonProperties.class})
@Slf4j
public class RedissonAutoConfiguration {@Bean@ConditionalOnMissingBean({RedisConnectionFactory.class})public RedissonConnectionFactory redissonConnectionFactory(RedissonClient redisson) {return new RedissonConnectionFactory(redisson);}@Bean(destroyMethod = "shutdown")@ConditionalOnMissingBean({RedissonClient.class})public RedissonClient redisson(RedissonProperties redissonProperties) throws IOException {Config config = new Config();config.useClusterServers().addNodeAddress(redissonProperties.getNodeAddresses().split(",")).setScanInterval(redissonProperties.getScanInterval());config.setThreads(redissonProperties.getThreads()).setNettyThreads(redissonProperties.getNettyThreads()).setTransportMode(TransportMode.valueOf(redissonProperties.getTransportMode()));return Redisson.create(config);}@Bean@ConditionalOnMissingBean(name = {"redisTemplate"})public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) throws UnknownHostException {RedisTemplate<Object, Object> template = new RedisTemplate();template.setConnectionFactory(redisConnectionFactory);return template;}@Bean@ConditionalOnMissingBeanpublic StringRedisTemplate stringRedisTemplate(RedisConnectionFactory redisConnectionFactory) throws UnknownHostException {StringRedisTemplate template = new StringRedisTemplate();template.setConnectionFactory(redisConnectionFactory);return template;}}
redis的緩存類實現
@Service
public class RedisCache {@Autowiredprivate RedissonClient redisson;@Autowiredprivate RedissonProperties redissonProperties;/*** 緩存** @param key 緩存key* @param <T>* @return 緩存返回值*/public <T> T get(String key) {RBucket<T> bucket = redisson.getBucket(getKey(key));return bucket.get();}/*** 以string的方式讀取緩存** @param key 緩存key* @return 緩存返回值*/public String getString(String key) {RBucket<String> bucket = redisson.getBucket(getKey(key), StringCodec.INSTANCE);return bucket.get();}/*** 以string的方式保存緩存(與其他應用共用redis時需要使用該函數)** @param key 緩存key* @param value 緩存值* @param expiredTime 緩存過期時間*/public void putString(String key, String value, long expiredTime) {RBucket<String> bucket = redisson.getBucket(getKey(key), StringCodec.INSTANCE);bucket.set(value, expiredTime, TimeUnit.MILLISECONDS);}/*** 如果不存在則寫入緩存(string方式,不帶有redisson的格式信息)** @param key 緩存key* @param value 緩存值* @param expiredTime 緩存過期時間*/public boolean putStringIfAbsent(String key, String value, long expiredTime) {RBucket<String> bucket = redisson.getBucket(getKey(key), StringCodec.INSTANCE);return bucket.trySet(value, expiredTime, TimeUnit.MILLISECONDS);}/*** 設置緩存** @param key 緩存key* @param value 緩存值* @param expiredTime 緩存過期時間* @param <T> 類型*/public <T> void put(String key, T value, long expiredTime) {RBucket<T> bucket = redisson.getBucket(getKey(key));bucket.set(value, expiredTime, TimeUnit.MILLISECONDS);}/*** 如果不存在則設置緩存** @param key 緩存key* @param value 緩存值* @param expiredTime 緩存過期時間* @param <T> 類型*/public <T> void putIfAbsent(String key, T value, long expiredTime) {RBucket<T> bucket = redisson.getBucket(getKey(key));bucket.trySet(value, expiredTime, TimeUnit.MILLISECONDS);}/*** 移除緩存** @param key*/public void remove(String key) {redisson.getBucket(getKey(key)).delete();}/*** 判斷緩存是否存在** @param key* @return*/public boolean exists(String key) {return redisson.getBucket(getKey(key)).isExists();}private String getKey(String key) {return StringUtils.format("{0}:{1}", redissonProperties.getKeyPrefix(), key);}
獲取和釋放分布式鎖接口
DistributedLock
/*** get分布式鎖* @param lockKey* @param requestId* @param expireTime* @return*/public boolean getDistributedLock(String lockKey, String requestId, long expireTime);/*** remove分布式鎖* @param lockKey* @param requestId* @return*/public boolean removeDistributedLock(String lockKey, String requestId);
實現DistributedLock的實現類邏輯
@Service
public class RedisDistributedLocker implements DistributedLocker {private static final Logger logger = LoggerFactory.getLogger(RedisDistributedLocker.class);@Autowiredprivate RedissonClient redisson;@Autowiredprivate RedissonProperties redissonProperties;public boolean getDistributedLock(String lockKey, String flagId, long expireTime) {boolean success;try {if (expireTime == 0) {expireTime = redissonProperties.getLeaseTime();}lockKey = StringUtils.format("{0}:{1}", redissonProperties.getKeyPrefix(), lockKey);RLock locker = redisson.getLock(lockKey);success = locker.tryLock(redissonProperties.getWaitTime(), expireTime, TimeUnit.MILLISECONDS);} catch (Exception e) {success = false;logger.error(StringUtils.format("獲取分布式鎖失敗,lockKey={0}, flagId={1}, expirTime={2}", lockKey, flagId, expireTime), e);}return success;}public boolean releaseDistributedLock(String lockKey, String flagId) {boolean success = false;try {lockKey = StringUtils.format("{0}:{1}", redissonProperties.getKeyPrefix(), lockKey);RLock locker = redisson.getLock(lockKey);if (locker.isHeldByCurrentThread()) {locker.unlock();success = true;}} catch (Exception e) {success = false;logger.error(StringUtils.format("分布式鎖失敗,lockKey={0}, flagId={1}", lockKey, flagId), e);}return success;}
在需要的業務場景下使用 以下為偽代碼
try {boolean ock = distributedLocker.getDistributedLock(lockKey, flagId, 9000L);if (!ock) {return;}// 實現自己的業務邏輯。。。。。。。。。。。。。。。。。。。。。。。。。} catch (Exception e) {e.printStackTrace();throw new RuntimeException(e.getMessage());} finally {distributedLocker.releaseDistributedLock(lockKey, flagId);}
以上的是分布式鎖之RedissonLock 若需完整代碼 可識別二維碼后 給您發代碼。