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();
}