好久没来博客了,遇到了一些好东西分享给大家,不喜勿喷!
redisson是基于redis 的一种开源框架,该框架是为了方便我们使用redis而再度封装的一个框架。也不多做介绍了。
官方文档连接:https://github.com/redisson/redisson/wiki/%E7%9B%AE%E5%BD%95
在我们项目中,它来干什么呢?我想到是结合aop和自定义注解实现redis的分布式锁控制,使我们的加锁解锁得以统一控制。接下来期待下吧!上代码。
pom如下:
org.redisson
redisson
3.11.6
首先需要我们在容器中注入redisClient。我们的redisConfig配置类如下
/**
* 启动程序的时候来初始化这个类
@PropertySource 加载指定配置文件
*/
@Configuration
@PropertySource("classpath:config/redis.properties")
public class RedisConfig {
// #Matser的ip地址
@Value("${redis.hostName}")
private String MASTER_HOST;
//#端口号
@Value("${redis.port}")
private Integer PORT;
// 密码
@Value("${redis.password}")
private String PASSWORD;
//最大空闲数
@Value("${redis.maxIdle}")
private Integer maxIdle;
public RedisConfig() {
System.out.println("初始化redisTemplate。。。。。。。。。。。");
}
@Bean(name = "redisClient")
public RedissonClient redisClient() {
Config config = new Config();
config.useSingleServer()
//.setPassword(PASSWORD)
.setTimeout(1000000)
//这里注意address 必须redis:// 或者rediss:// 开头
// 不然会报错
.setAddress("redis://127.0.0.1:6379");
// .setConnectionMinimumIdleSize(maxWaitMillis)
;
return Redisson.create(config);
}
}
接下来使我们的自定义注解 :
/**
* 自定义分布式锁注解 配合 aop + Redisson 实现分布式锁
*/
@Target({ ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface RedisDistlock {
/**
* 锁的名称。 如果lockName可以确定,直接设置该属性。
*/
String lockName() default "";
/**
*
* 获取注解的方法参数列表的某个参数对象的某个属性值来作为lockName。因为有时候lockName是不固定的。
* 当param不为空时,可以通过argNum参数来设置具体是参数列表的第几个参数,不设置则默认取第一个。
*
*/
String param() default "";
/**
* 获得锁名时拼接前后缀用到的分隔符
*
* @return
*/
String separator() default ":";
/**
* 锁超时时间。 超时时间过后,锁自动释放 默认8秒。 建议: 尽量缩简需要加锁的逻辑。
*/
long leaseTime() default 8L;
/**
* 时间单位。默认为秒。
*/
TimeUnit timeUnit() default TimeUnit.SECONDS;
}
aop实现如下:
/**
* redis分布式锁 切面处理
* aop 切面处理 redisson分布式加锁操作
*
* @author chenhengtong
*/
@Aspect
@Component("admincenterRedisDistlockAspect")
@Log4j
@Order(-1)
public class RedisDistlockAspect {
/**
* 分布式锁 key
*/
public static final String REDIS_DISTLOCK_PREFIX = "distlock:%s";
@Autowired
private RedissonClient redissonClient;
/**
* 切入点为加了 @RedissonLock 注解
*/
@Pointcut("@annotation(com.ssq.www.springboot.aspect.RedisDistlock)")
public void RedissonLockAspect() {
}
@Around("RedissonLockAspect()")
public Object lockAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
Method method = null;
RedisDistlock redisDistlock;
RLock rLock = null;
long start = 0L;
try {
method = getPointMethod(proceedingJoinPoint);
// 获取方法上的分布式锁注解
redisDistlock = method.getAnnotation(RedisDistlock.class);
long expireTime = redisDistlock.leaseTime();
String teamSequence = getTeamSequence(proceedingJoinPoint);
String distlockKey = String.format(REDIS_DISTLOCK_PREFIX, teamSequence);
System.out.println("加锁 key distlockKey = " + distlockKey);
start = System.currentTimeMillis();
//获取锁
rLock = redissonClient.getLock(distlockKey);
//设置超时
rLock.lock(expireTime, redisDistlock.timeUnit());
return proceedingJoinPoint.proceed();
} finally {
try {
if (rLock != null && rLock.isLocked()) {
rLock.unlock();
}
log.info("锁释放完成");
} catch (Exception e) {
log.error("redis 分布式锁释放异常!", e);
}
String methodName = method.getName();
log.info(">> " + methodName + " cost " + (System.currentTimeMillis() - start) + " ms");
}
}
/**
* 获取切入点的方法
*
* @param joinPoint
* @return
*/
private Method getPointMethod(JoinPoint joinPoint) {
Signature signature = joinPoint.getSignature();
MethodSignature methodSignature = (MethodSignature) signature;
return methodSignature.getMethod();
}
/**
* 通过方法参数获取车队序列号的值
*
* @param joinPoint
* @return
*/
private String getTeamSequence(JoinPoint joinPoint) {
Signature signature = joinPoint.getSignature();
MethodSignature methodSignature = (MethodSignature) signature;
// 参数名
String[] parameterNames = methodSignature.getParameterNames();
// 参数值对象
Object[] parameterValues = joinPoint.getArgs();
Method method = getPointMethod(joinPoint);
RedisDistlock rlock = method.getAnnotation(RedisDistlock.class);
String teamSequence = null;
String lockName = rlock.lockName();
String param = rlock.param();
String separator = rlock.separator();
if (StringUtils.isEmpty(lockName)) {
lockName = method.getName();
}
if (!StringUtils.isEmpty(parameterValues)) {
for (int i = 0; i < parameterNames.length; i++) {
//未设置pram考虑 取第一个参数值
if (StringUtils.isEmpty(param)) {
param = parameterValues[i].toString();
teamSequence = lockName + separator + param;
break;
} else if (param.equalsIgnoreCase(parameterNames[i])) {
teamSequence = lockName + separator + parameterValues[i].toString();
break;
} else {
teamSequence = reflectTeamSequence(parameterValues[i], param);
if (StringUtils.isEmpty(teamSequence)) {
continue;
}
teamSequence = lockName + separator + teamSequence;
break;
}
}
if (!StringUtils.isEmpty(teamSequence)) {
return teamSequence;
}
}
throw new RuntimeException("锁ID为空");
}
/**
* 反射获取 注解制定的参数
*
* @param param 方法上的参数对象
* @return
*/
private String reflectTeamSequence(Object param, String paramName) {
if (param == null) {
return "";
}
// 1. 获取其从父类继承下来的所有字段( Object.class 排除)
List fieldList = new ArrayList<>();
Class> clazz = param.getClass();
while (clazz != null && !clazz.equals(Object.class)) {
fieldList.addAll(Arrays.asList(clazz.getDeclaredFields()));
clazz = clazz.getSuperclass();
}
// 2. 返回参数的值
for (Field field : fieldList) {
field.setAccessible(true);
// 字段名称
String fieldName = field.getName();
Object fieldValue;
if (paramName.equalsIgnoreCase(fieldName)) {
try {
fieldValue = field.get(param);
if (!StringUtils.isEmpty(fieldValue)) {
return fieldValue.toString();
}
} catch (IllegalAccessException e) {
// 已经设置了accessible ...
log.error("join pointer reflect get paramName error!", e);
}
break;
}
}
return "";
}
}
以上就是今天要讲的内容,本文仅仅简单介绍了redisson的一种使用,希望对大家有用。