springboot通过redis实现分布式锁实现并调用
来源:互联网 发布:Windows 设置在哪里 编辑:程序博客网 时间:2024/06/07 20:25
import org.springframework.data.redis.core.RedisTemplate;
public class RedisLock {
private RedisTemplate redisTemplate;
/**
* 重试时间
*/
private static final int DEFAULT_ACQUIRY_RETRY_MILLIS = 100;
/**
* 锁的后缀
*/
private static final String LOCK_SUFFIX = "_redis_lock";
/**
* 锁的key
*/
private String lockKey;
/**
* 锁超时时间,防止线程在入锁以后,防止阻塞后面的线程无法获取锁
*/
private int expireMsecs = 60 * 1000;
/**
* 线程获取锁的等待时间
*/
private int timeoutMsecs = 10 * 1000;
/**
* 是否锁定标志
*/
private volatile boolean locked = false;
/**
* 构造器
*
* @param redisTemplate
* @param lockKey 锁的key
*/
public RedisLock(String lockKey) {
this.redisTemplate = (RedisTemplate) SpringContextUtil.getBean("clusterRedisTemplate");
this.lockKey = lockKey + LOCK_SUFFIX;
}
/**
* 构造器
*
* @param redisTemplate
* @param lockKey 锁的key
* @param timeoutMsecs 获取锁的超时时间
*/
public RedisLock(String lockKey, int timeoutMsecs) {
this(lockKey);
this.timeoutMsecs = timeoutMsecs;
}
/**
* 构造器
*
* @param redisTemplate
* @param lockKey 锁的key
* @param timeoutMsecs 获取锁的超时时间
* @param expireMsecs 锁的有效期
*/
public RedisLock(String lockKey, int timeoutMsecs, int expireMsecs) {
this(lockKey, timeoutMsecs);
this.expireMsecs = expireMsecs;
}
public String getLockKey() {
return lockKey;
}
/**
* 封装和jedis方法
*
* @param key
* @return
*/
private String get(final String key) {
Object obj = redisTemplate.opsForValue().get(key);
return obj != null ? obj.toString() : null;
}
/**
* 封装和jedis方法
*
* @param key
* @param value
* @return
*/
private boolean setNX(final String key, final String value) {
return redisTemplate.opsForValue().setIfAbsent(key, value);
}
/**
* 封装和jedis方法
*
* @param key
* @param value
* @return
*/
private String getSet(final String key, final String value) {
Object obj = redisTemplate.opsForValue().getAndSet(key, value);
return obj != null ? (String) obj : null;
}
/**
* 获取锁
*
* @return 获取锁成功返回ture,超时返回false
* @throws InterruptedException
*/
public synchronized boolean lock() throws InterruptedException {
int timeout = timeoutMsecs;
while (timeout >= 0) {
long expires = System.currentTimeMillis() + expireMsecs + 1;
String expiresStr = String.valueOf(expires); // 锁到期时间
if (this.setNX(lockKey, expiresStr)) {
locked = true;
return true;
}
// redis里key的时间
String currentValue = this.get(lockKey);
// 判断锁是否已经过期,过期则重新设置并获取
if (currentValue != null && Long.parseLong(currentValue) < System.currentTimeMillis()) {
// 设置锁并返回旧值
String oldValue = this.getSet(lockKey, expiresStr);
// 比较锁的时间,如果不一致则可能是其他锁已经修改了值并获取
if (oldValue != null && oldValue.equals(currentValue)) {
locked = true;
return true;
}
}
timeout -= DEFAULT_ACQUIRY_RETRY_MILLIS;
// 延时
Thread.sleep(DEFAULT_ACQUIRY_RETRY_MILLIS);
}
return false;
}
/**
* 释放获取到的锁
*/
public synchronized void unlock() {
if (locked) {
redisTemplate.delete(lockKey);
locked = false;
}
}
}
//锁的使用
@RequestMapping(value = "/xx", method = RequestMethod.POST)
public void xx(HttpSession session, String custId) {
LoginUserVO user = (LoginUserVO)session.getAttribute("user");
if(user == null) {
return RestResponseUtil.err(ServiceErrorCode.LOGIN_EXPIRE.getCode(),"未拿到当前登录用户信息!");
}
//判断当前用户custId和前端的custId是否一致
if(!user.getCustId().equals(custId)){
return RestResponseUtil.err(ServiceErrorCode.CUST_INFO_MODIFY_ERROR.getCode(),"客户信息被篡改!");
}
RedisLock lock = new RedisLock("unionCaptcha_" + custId);
try {
//没有获取到锁
if (!lock.lock()) {
return RestResponseUtil.err(ServiceErrorCode.REQUEST_REPEAT_ERROR.getCode(), "请不要频繁请求验证码!");
}
//获取到锁
//调用服务
} catch (ServiceException e) {
log.error("custId : " + custId + "xx:", e);
} catch (Exception e) {
log.error("custId : " + custId + "请求异常:", e);
} finally {
//释放锁
lock.unlock();
}
}
//applicationContext工具类
public class SpringContextUtil {
private static ApplicationContext applicationContext;
//获取上下文
public static ApplicationContext getApplicationContext() {
return applicationContext;
}
//设置上下文
public static void setApplicationContext(ApplicationContext applicationContext) {
SpringContextUtil.applicationContext = applicationContext;
}
//通过名字获取上下文中的bean
public static Object getBean(String name){
return applicationContext.getBean(name);
}
//通过类型获取上下文中的bean
public static Object getBean(Class<?> requiredType){
return applicationContext.getBean(requiredType);
}
}
@SpringBootApplication
@ComponentScan(basePackages={"com.lixy"})
@EnableAsync
public class Application {
public static void main(String[] args) throws Exception {
SpringApplication application = new SpringApplication(Application.class);
//applicationContext放入工具类
SpringContextUtil.setApplicationContext(application.run(args));
}
}
//redis的注入
@Configuration
public class GlobalConfig {
private final static int DEFAULT_TIMEOUT = 5000;
private final static int DEFAULT_MAX_ATTEMPTS = 6;
@Bean
@ConditionalOnMissingBean
public JedisCluster jedisCLuster(@Qualifier("redisPoolConfig") RedisPoolConfig redisPoolConfig) {
//redis集群主节点
String[] servers = [192.168.10.177:7000,192.168.10.178:7000,192.168.10.204:7000];
Set<HostAndPort> nodes = new HashSet<>();
for (String server : servers) {
String[] hostAndPort = server.split(":");
nodes.add(new HostAndPort(hostAndPort[0], Integer.parseInt(hostAndPort[1])));
}
//redis密码
String password = "password***";
if (StringUtils.isEmpty(password)) {
return new JedisCluster(nodes, redisPoolConfig);
}
return new JedisCluster(nodes, DEFAULT_TIMEOUT, DEFAULT_TIMEOUT, DEFAULT_MAX_ATTEMPTS, password, redisPoolConfig);
}
@Bean
@ConditionalOnMissingBean
public RedisConnectionFactory connectionFactory() {
String[] servers = [192.168.10.177:7000,192.168.10.178:7000,192.168.10.204:7000];
JedisConnectionFactory factory = new JedisConnectionFactory(new RedisClusterConfiguration(Arrays.asList(servers)));
factory.setPassword("password***");
return factory;
}
@SuppressWarnings({"rawtypes", "unchecked"})
@Bean(name = "clusterRedisTemplate")
public RedisTemplate<String, String> redisTemplate() {
RedisTemplate template = new RedisTemplate();
template.setConnectionFactory(connectionFactory());
// 开启事务支持
template.setEnableTransactionSupport(true);
// 使用String格式序列化缓存键
StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
template.setKeySerializer(stringRedisSerializer);
template.setHashKeySerializer(stringRedisSerializer);
// 使用json格式序列化缓存值
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
ObjectMapper om = new ObjectMapper();
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
jackson2JsonRedisSerializer.setObjectMapper(om);
template.setValueSerializer(jackson2JsonRedisSerializer);
template.setDefaultSerializer(jackson2JsonRedisSerializer);
template.afterPropertiesSet();
return template;
}
}
@ConfigurationProperties("redis.pool")
@Component("redisPoolConfig")
@Order(10)
public class RedisPoolConfig extends JedisPoolConfig {
}
阅读全文
0 0
- springboot通过redis实现分布式锁实现并调用
- 通过Redis实现分布式锁
- Redis实现分布式锁
- Redis 分布式锁实现
- Redis 分布式锁实现
- Redis实现分布式锁
- redis实现分布式锁
- Redis实现分布式锁
- 分布式锁redis实现
- Redis 分布式锁实现
- redis分布式锁实现
- redis实现分布式锁
- Redis分布式锁实现
- redis分布式锁实现
- redis实现分布式锁
- Redis分布式锁实现
- Redis实现分布式锁
- Redis实现分布式锁
- ubuntu下python在pycharm环境下安装setuptools和pip
- sql解释执行顺序
- 数据结构实验之图论八:欧拉回路
- Android 简单GreenDao增删改查
- openssl证书使用说明02
- springboot通过redis实现分布式锁实现并调用
- 获取系统用户IP地址
- Some things about the ASCII,Unicode and UTF-8
- 字典中items(),keys(),values()
- 数据结构(简介)
- 静态库&&动态库:lib和dll文件的区别和联系
- python报错invalid character in identifier
- openssl生成cer、pfx、crt
- MATLABR2012a如何激活