redis分布式锁做切面,一个注解统一使用锁

1. 自定义注解

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

@Retention(RetentionPolicy.RUNTIME)
public @interface RedisLock {
    String[] keyPieces();
    int expireTime() default 5;
}

2.aop切面

@Slf4j
@Aspect
@Component
public class RedisLockAspect {

    @Autowired
    private RedisService redisService;

    @Around("@annotation(redisLock)")
    public Object doAround(ProceedingJoinPoint pjp, RedisLock redisLock) throws Throwable {
        String key = parseKey(pjp, redisLock.keyPieces());
        if (redisService.setNx(key, System.currentTimeMillis() + "", redisLock.expireTime())) {
            try {
                Object obj = pjp.proceed();
                return obj;
            } finally {
                redisService.delete(key);
            }
        } else {
            throw new BusinessException(HttpStatus.BAD_REQUEST.value(), "系统繁忙,请稍后再试");
        }
    }

    // 解析实际参数的key
    private String parseKey(ProceedingJoinPoint proceedingJoinPoint, String[] cacheKey)
            throws IllegalAccessException {
        StringBuilder sb = new StringBuilder();
        for (String keyPiece : cacheKey) {
            if (keyPiece.contains("#")) {
                String key = keyPiece.replace("#", "");
                StringTokenizer stringTokenizer = new StringTokenizer(key, ".");
                Map<String, Object> nameAndValue = getNameAndValue(proceedingJoinPoint);
                Object actualKey = null;
                while (stringTokenizer.hasMoreTokens()) {
                    if (actualKey == null) {
                        actualKey = nameAndValue.get(stringTokenizer.nextToken());
                    } else {
                        actualKey = getPropValue(actualKey, stringTokenizer.nextToken());
                    }
                }
                sb.append(actualKey).append("_");
            } else {
                sb.append(keyPiece).append("_");
            }
        }
        sb.deleteCharAt(sb.length() - 1);
        return sb.toString();
    }

    /**
     * 获取参数Map集合
     * @param joinPoint 切面
     */
    private static Map<String, Object> getNameAndValue(ProceedingJoinPoint joinPoint) {
        Object[] paramValues = joinPoint.getArgs();
        String[] paramNames = ((CodeSignature) joinPoint.getSignature()).getParameterNames();
        Map<String, Object> param = new HashMap<>(paramNames.length);
        for (int i = 0; i < paramNames.length; i++) {
            param.put(paramNames[i], paramValues[i]);
        }
        return param;
    }

    /**
     * 获取指定参数名的参数值
     */
    public static Object getPropValue(Object obj, String propName) throws IllegalAccessException {
        Field[] fields = obj.getClass().getDeclaredFields();
        for (Field f : fields) {
            if (f.getName().equals(propName)) {
                //在反射时能访问私有变量
                f.setAccessible(true);
                return f.get(obj);
            }
        }
        return null;
    }
}

3. 业务类,使用注解实现锁,这样减少代码编写

@RedisLock(keyPieces = {PREFIX, "#talkId", "#currentUser"}, expireTime = 3)
    public List<VoteItemVO> cancelVote(Integer talkId, String currentUser) {
        VoteVO voteInfo = getVoteVO(talkId, currentUser);
        List<Integer> itemList = new ArrayList<>();
        //判断是否投过票
        if (!voteUserService.isVoted(currentUser, voteInfo.getId())) {
            throw new BizException(BasicErrorCode.BIZ_ERROR, "你还没投过票,无法取消哦");
        }
        deleteVote(currentUser, talkId);
        return voteItemService.getVoteItems(voteInfo.getId(), currentUser);
    }

或者:   可以访问到实体类的子段

@RedisLock(keyPieces = {PREFIX, "#commentDTO.sourceId", "#commentDTO.parentId", "#ticket"})
    public Integer saveOrUpdate(CommentDTO commentDTO, String ticket) {
        CommentDraft commentDraft = this.convertModel(commentDTO, ticket);
        CommentDraftVO historyDraft = getDraft(commentDTO.getSourceId(), commentDTO.getParentId(), ticket);
        if (Objects.isNull(historyDraft)) {
            commentDraftMapper.insertSelective(commentDraft);
        } else {
            commentDraft.setId(historyDraft.getId());
            commentDraftMapper.updateByPrimaryKeySelective(commentDraft);
        }
        pictureService.saveOrUpdate(Source.commentDraft, commentDraft.getId(), commentDTO.getPictures());
        return commentDraft.getId();
    }

猜你喜欢

转载自blog.csdn.net/qq_39809613/article/details/110244257