Commit 8f09d46a authored by liuxingyu's avatar liuxingyu

首次提交

parent a5f948d8
/*
* Copyright (c) 2020 牧星仓库管理系统 All rights reserved.
*
* http://www.mushiny.com
*
* 版权所有,侵权必究!
*/
package com.mushiny.redisson.annotation;
import com.mushiny.redisson.enums.LockType;
import java.lang.annotation.*;
import java.util.concurrent.TimeUnit;
/**
* 操作分布式锁
*
* @author
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface RedissonLock {
/** 锁类型*/
LockType lockType() default LockType.FAIR_LOCK;
/** 获取锁等待时间,默认12秒*/
long waitTime() default 12000L;
/** 锁自动释放时间,默认10秒*/
long leaseTime() default 10000L;
/** 时间单位(获取锁等待时间和持锁时间都用此单位)*/
TimeUnit unit() default TimeUnit.MILLISECONDS;
}
\ No newline at end of file
package com.mushiny.redisson.aspect;
import com.mushiny.redisson.annotation.RedissonLock;
import com.mushiny.redisson.execption.RedissonErrorCode;
import com.mushiny.redisson.execption.RedissonException;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.lang.reflect.Method;
/**
* 数据过滤,切面处理类
*
* @author lxy
* @since 0.0.1
*/
@Aspect
@Component
@Slf4j
public class RedissonLockAspect {
final String LOCKED = "REDISSON-LOCK";
@Autowired
RedissonClient redissonClient;
@Pointcut("@annotation(com.mushiny.redisson.annotation.RedissonLock)")
public void pointCut() {
}
/**
* 公平锁切面
*/
@Around("pointCut()")
public Object around(ProceedingJoinPoint point) throws Throwable {
System.out.println("开始加锁");
Signature sig = point.getSignature();
MethodSignature methodSig = (MethodSignature) sig;
Object target = point.getTarget();
// 获取当前注解方法
Method currentMethod = target.getClass().getMethod(methodSig.getName(), methodSig.getParameterTypes());
RedissonLock lockAction = currentMethod.getAnnotation(RedissonLock.class);
// 方法名+入参进行加锁
StringBuilder args = new StringBuilder();
//加锁key以REDISSONLOCK开头
String key = LOCKED + currentMethod.getName() + "_" + args;
//这里根据wms场景需要,放的是公平锁,也可自行修改为重入锁和红锁
RLock lock = getLock(key, lockAction);
// 具有Watch Dog 自动延期机制 默认续30s
boolean locked = lock.tryLock(lockAction.waitTime(),-1,lockAction.unit());
//加锁失败给前端返回码
if (!locked) {
log.error("加锁:{}失败,请重新尝试", currentMethod.getName());
throw new RedissonException(RedissonErrorCode.METHOD_IN_EXECUTION);
}
try {
// 加锁成功执行业务方法
return point.proceed();
} catch (Exception e) {
log.error("执行方法:{}失败,请重新尝试", currentMethod.getName());
} finally {
//执行完成需要释放掉锁
lock.unlock();
}
return null;
}
private RLock getLock(String key, RedissonLock lockAction) {
switch (lockAction.lockType()) {
case REENTRANT_LOCK:
return redissonClient.getLock(key);
case FAIR_LOCK:
return redissonClient.getFairLock(key);
case READ_LOCK:
return redissonClient.getReadWriteLock(key).readLock();
case WRITE_LOCK:
return redissonClient.getReadWriteLock(key).writeLock();
default:
throw new RuntimeException("do not support lock type:" + lockAction.lockType().name());
}
}
}
package com.mushiny.redisson.config;
import org.redisson.Redisson;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* 描述信息
*
* @auther lxy
* @since 2023/8/4 13:39
*/
@Configuration
public class RedissonManager {
@Value("${spring.redis.host}")
private String addresses;
@Value("${spring.redis.password}")
private String password;
@Value("${spring.redis.port}")
private String port;
@Bean(destroyMethod = "shutdown")
public RedissonClient redissonClient() {
Config config = new Config();
//调用 useSingleServer 方法,选择单机模式,并指定 Redis 服务器的地址
config.useSingleServer().setAddress("redis://" + addresses + ":" + port).setPassword(password);
System.out.println("redis://" + addresses + ":" + port);
//调用 setConnectionMinimumIdleSize 方法,设置连接池最小空闲连接数为 10。
config.useSingleServer().setConnectionMinimumIdleSize(10);
//调用 Redisson.create 方法,创建一个 RedissonClient 对象
RedissonClient redissonClient = Redisson.create(config);
return redissonClient;
}
}
package com.mushiny.redisson.controller;
import com.mushiny.redisson.enums.LockType;
import com.mushiny.redisson.utils.RedissonLockUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.text.SimpleDateFormat;
import java.util.Date;
@RestController
@Slf4j
public class PingApiForTestContraller {
@Autowired
RedissonLockUtil redissonLockUtil;
@PostMapping("api/ping")
public int pingApi(@RequestParam String storageBinCode, @RequestParam Long workStationId, @RequestParam Long warehouseId) {
String threadId = Thread.currentThread().getName() + Thread.currentThread().getId();
redissonLockUtil.getLockByKey(storageBinCode + workStationId + warehouseId, LockType.READ_LOCK.value());
Boolean getLock = redissonLockUtil.tryLock(null, storageBinCode + workStationId + warehouseId, LockType.REENTRANT_LOCK.value());
if (getLock) {
System.out.println(threadId + "拿锁成功");
try {
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date startDate = new Date();
System.out.println(threadId + "执行调度ping" + dateFormat.format(startDate));
Thread.sleep(10000);
System.out.println("结束时间为" + dateFormat.format(new Date()));
} catch (Exception e) {
e.printStackTrace();
}
} else {
System.out.println("拿锁失败");
return 1;
}
return 1;
}
}
/**
* Copyright (c) 2019 人人开源 All rights reserved.
* <p>
* https://www.renren.io
* <p>
* 版权所有,侵权必究!
*/
package com.mushiny.redisson.enums;
/**
* 行政区域 级别枚举
*
* @author Elen elen.shen@mushiny.comn
* @since 2.1.0
*/
public enum LockType {
/**
* 重入锁
*/
REENTRANT_LOCK(1),
/**
* 公平锁
*/
FAIR_LOCK(2),
/**
* 红锁
*/
READ_LOCK(3),
/**
* 读写锁
*/
WRITE_LOCK(4);
private final int value;
LockType(Integer value) {
this.value = value;
}
public Integer value() {
return this.value;
}
}
/*
* Copyright (c) 2020 牧星仓库管理系统 All rights reserved.
*
* http://www.mushiny.com
*
* 版权所有,侵权必究!
*/
package com.mushiny.redisson.execption;
/**
* 错误编码,由5位数字组成,前2位为模块编码,后3位为业务编码
* <p>
* 如:10001(10代表系统模块,001代表业务代码)
* </p>
*
* @author Elen elen.shen@mushiny.comn
* @since 2.1.0
*/
public interface RedissonErrorCode {
int INTERNAL_SERVER_ERROR = 500;
int METHOD_IN_EXECUTION = 10029;
}
/*
* Copyright (c) 2020 牧星仓库管理系统 All rights reserved.
*
* http://www.mushiny.com
*
* 版权所有,侵权必究!
*/
package com.mushiny.redisson.execption;
/**
* 自定义异常
*
* @author Elen elen.shen@mushiny.comn
* @since 2.1.0
*/
public class RedissonException extends RuntimeException {
private static final long serialVersionUID = 1L;
private int code;
private String msg;
public RedissonException(int code) {
this.code = code;
this.msg = "pls wait to try";
}
}
\ No newline at end of file
package com.mushiny.redisson.utils;
import com.mushiny.redisson.execption.RedissonErrorCode;
import com.mushiny.redisson.execption.RedissonException;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.ObjectUtils;
import java.util.concurrent.TimeUnit;
/**
* 描述信息
*
* @auther lxy0
* @since 2023/8/7 13:27
*/
@Slf4j
@Component
public class RedissonLockUtil {
public static final Long WAITTIME = 12000L;
public static final Long RELEASETIME = 14000L;
@Autowired
RedissonClient redissonClient;
/**
* @param key
* @param lockType REENTRANT_LOCK:可重入锁 FAIR_LOCK:公平锁 READ_LOCK:红锁 WRITE_LOCK:读写锁
* @return
*/
public RLock getLockByKey(String key, int lockType) {
if (ObjectUtils.isEmpty(key)) {
key = Thread.currentThread().getName() + ":" + Thread.currentThread().getId();
}
if (ObjectUtils.isEmpty(lockType)) {
lockType = 1;
}
switch (lockType) {
case 1:
return redissonClient.getLock(key);
case 2:
return redissonClient.getFairLock(key);
case 3:
return redissonClient.getReadWriteLock(key).readLock();
case 4:
return redissonClient.getReadWriteLock(key).writeLock();
default:
throw new RuntimeException("do not support lock type:" + lockType);
}
}
/**
* 非阻塞式,在1s内尝试获取锁
* 获取成功默认锁30s,过期看门狗自动续期
*
* @param key
* @param waitTime
* @param type
* @return
*/
public Boolean tryLock(Long waitTime, String key, int type) {
boolean lock = false;
if (ObjectUtils.isEmpty(waitTime)) {
waitTime = WAITTIME;
}
try {
RLock rLock = getLockByKey(key, type);
lock = rLock.tryLock(waitTime, TimeUnit.MILLISECONDS);
if (!lock) {
log.error("分布式锁加锁:{}失败,请重新尝试");
throw new RedissonException(RedissonErrorCode.METHOD_IN_EXECUTION);
}
} catch (Exception e) {
e.printStackTrace();
}
return lock;
}
/**
* 当releaseTime传的是-1或者是空时,开启watch dog模式,会开启自动续锁
* 非阻塞式
* @param waitTime 等待时间
* @param releaseTime 锁有效时间
* @param key
* @param type
* @return
*/
public Boolean tryLock(Long waitTime, Long releaseTime, String key, int type) {
boolean lock = false;
if (ObjectUtils.isEmpty(waitTime)) {
waitTime = WAITTIME;
}
if (ObjectUtils.isEmpty(releaseTime)) {
releaseTime = RELEASETIME;
}
try {
RLock rLock = getLockByKey(key, type);
lock = rLock.tryLock(waitTime, releaseTime, TimeUnit.MILLISECONDS);
if (!lock) {
log.error("分布式锁加锁:{}失败,请重新尝试");
throw new RedissonException(RedissonErrorCode.METHOD_IN_EXECUTION);
}
} catch (Exception e) {
e.printStackTrace();
}
return lock;
}
/**
* 手动释放 redissonLock 锁
*
* @param key
* @return
*/
public boolean releaseLock(String key, int type) {
String threadName = Thread.currentThread().getName() + ":" + Thread.currentThread().getId();
try {
RLock rLock = getLockByKey(key, type);
rLock.unlock();
if (!rLock.isLocked()) {
log.debug("已删除锁{}成功,当前线程:{}", key, threadName);
return true;
} else if (rLock.isHeldByCurrentThread()) {
log.debug("未删除锁{},还需当前线程解锁{}次,当前线程:{}", key, rLock.getHoldCount(), threadName);
return true;
} else {
log.warn("未删除锁{},还需其他线程解锁{}次,当前线程:{}", key, rLock.getHoldCount(), threadName);
return false;
}
} catch (Throwable e) {
log.error("解锁{}异常,返回false,当前线程:{}", key, threadName, e);
return false;
}
}
}
package com.mushiny.redisson;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
class MwmsRedissonApplicationTests {
@Test
void contextLoads() {
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment