1. 程式人生 > 其它 >基於redis分散式鎖註解實現

基於redis分散式鎖註解實現

基於redis分散式鎖註解實現

  • 1、編寫註解

  • 2、編寫切面

1、編寫註解

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.METHOD)  
@Retention(RetentionPolicy.RUNTIME)  
@Documented  
public @interface RedisLock { String key(); // 併發鎖key String value(); // 鎖定時長 預設單位秒 long ttl() default 5; }

2、編寫切面

import java.lang.reflect.Method;
import java.util.concurrent.TimeUnit;

import org.aspectj.lang.ProceedingJoinPoint;
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.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.DefaultParameterNameDiscoverer;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.Expression;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.stereotype.Component;

import com.yun.common.api.redis.RedisService;
import com.yun.common.
base.response.BusinessException; import com.yun.common.base.utils.AssertUtil; import lombok.extern.slf4j.Slf4j; @Aspect @Component @Slf4j public class RedisLockAspect { @Autowired private RedisService redisService; @Pointcut("execution(public * com.bgy.*.app.*.service..*.*(..))")
public void appPointCut(){}; @Pointcut("execution(public * com.bgy.*.domain..*.*(..))") public void domainPointCut(){}; @Around("(appPointCut() && @annotation(redisLock)) || (domainPointCut() && @annotation(redisLock)))") public Object before(ProceedingJoinPoint pJoinPoint, RedisLock redisLock) throws Throwable { String key = redisLock.key(); String value = redisLock.value(); long time = redisLock.ttl(); AssertUtil.notNull(key, "獲取併發鎖key為空。", key); AssertUtil.notNull(value, "獲取併發鎖value為空。", value); value = this.getRedisKey(pJoinPoint, value); String lockKey = key.concat(value); // 1、獲取鎖 RLock lock = redisService.getRLock(lockKey); // 2、鎖定 try { AssertUtil.isTrue(lock.tryLock(time, TimeUnit.SECONDS), "獲取併發鎖[%s]失敗。", lockKey); // 3、業務邏輯 return pJoinPoint.proceed(); } catch (BusinessException e) { log.error("獲取鎖失敗。", e); throw e; }finally { // 4、釋放鎖 lock.unlock(); } } private String getRedisKey(ProceedingJoinPoint pJoinPoint, String key) { //使用SpringEL表示式解析註解上的key SpelExpressionParser parser = new SpelExpressionParser(); Expression expression = parser.parseExpression(key); //獲取方法入參 Object[] parameterValues = pJoinPoint.getArgs(); //獲取方法形參 MethodSignature signature = (MethodSignature)pJoinPoint.getSignature(); Method method = signature.getMethod(); DefaultParameterNameDiscoverer nameDiscoverer = new DefaultParameterNameDiscoverer(); String[] parameterNames = nameDiscoverer.getParameterNames(method); if (parameterNames == null || parameterNames.length == 0) { //方法沒有入參,直接返回註解上的key return key; } //解析表示式 EvaluationContext evaluationContext = new StandardEvaluationContext(); // 給上下文賦值 for(int i = 0 ; i < parameterNames.length ; i++) { evaluationContext.setVariable(parameterNames[i], parameterValues[i]); } try { Object expressionValue = expression.getValue(evaluationContext); if (expressionValue != null && !"".equals(expressionValue.toString())) { //返回el解析後的key return expressionValue.toString(); }else{ //使用註解上的key return key; } } catch (Exception e) { //解析失敗,預設使用註解上的key return key; } } }