基于注解的分布式锁
在上一篇笔记中我们介绍了基于Redis的分布式锁,这一篇我们就介绍一下基于注解的方法去使用这个分布式锁,使用这种切面的方式可以有效的减少功能性代码对业务代码的侵入性。
本文中的RedisLockUtils链接
-
首先我们需要定义一个注解类,相当于定义一个切点
package com.example.demo.annotation; import java.lang.annotation.*; /** * @author : wulg29230 * @Date : 2020/3/9 14:36 **/ @Target({ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface RedisLock { /** * 入参的类型 * @return */ Class<?> type(); /** * 入参中作为redis锁的key字段 * @return */ String key(); /** * 获取锁等待时间 * @return */ long waitTime() default 0L; }
-
然后我们写一个切面类,针对切点做业务处理
package com.example.demo.aop; import com.example.demo.annotation.RedisLock; import com.example.demo.constant.BusinessExceptionEnum; import com.example.demo.exception.BusinessException; import com.example.demo.util.RedisLockUtils; import org.apache.dubbo.common.utils.StringUtils; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.springframework.stereotype.Component; import javax.annotation.Resource; import java.lang.reflect.Field; /** * @author : wulg29230 * @Date : 2020/3/9 14:41 **/ @Component @Aspect public class RedisLockInterceptor { @Resource private RedisLockUtils redisLockUtils; @Around("@annotation(redisLock)") public Object around(ProceedingJoinPoint pjp, RedisLock redisLock) throws Throwable { //切点作用的方法的参数 Object[] args = pjp.getArgs(); String lockKey = null; boolean flag = false; for(Object object : args) { //判断入参中是否有需要锁的对象 if(object.getClass().equals(redisLock.type())) { Field[] fields = object.getClass().getDeclaredFields(); for(Field field : fields){ field.setAccessible(true); if(redisLock.key().equals(field.getName())){ lockKey = field.get(object) == null ? "" : field.get(object).toString(); flag = true; break; } } } if(flag){ break; } } if(!StringUtils.isBlank(lockKey)){ //获取redis锁 if(redisLockUtils.lock(redisLock.key(),redisLock.waitTime())){ try { //执行方法 Object object = pjp.proceed(); return object; }finally { //释放锁 redisLockUtils.releaseLock(redisLock.key()); } }else{ throw new BusinessException(BusinessExceptionEnum.GET_REDIS_LOCK_FAIL); } }else{ //执行方法 Object object = pjp.proceed(); return object; } } }
-
最后我们只需要在需要加锁的方法上加上上面的注解就能让这个方法使用分布式锁了
@Override @RedisLock(type = UserInfoDTO.class,key = "userId",waitTime = 6000) public UserInfoDTO updateUserInfo(UserInfoDTO userInfoDTO){ UserInfo userInfo = BeanUtils.dtoTodo(userInfoDTO,UserInfo.class); userInfoMapper.updateByPrimaryKey(userInfo); try { log.info("开始睡觉,time = {}",new Date()); Thread.sleep(10000L); log.info("结束睡觉,time = {}",new Date()); } catch (InterruptedException e) { e.printStackTrace(); } return BeanUtils.doTodto(userInfo,UserInfoDTO.class); }