1.
luofl
2025-02-23 8c4f42c77afb6690fcc48ac219ae044173fd77dd
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
package com.panzhihua.sangeshenbian.aspectj;
 
import com.panzhihua.sangeshenbian.annotation.DistributedLock;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
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.redisson.api.RedissonClient;
import org.springframework.core.LocalVariableTableParameterNameDiscoverer;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.stereotype.Component;
 
import javax.annotation.Resource;
import java.lang.reflect.Method;
import java.util.Objects;
 
/**
 * @Desecription: 分布式锁切面
 * 注意!!!分布式锁不能加在事务方法当中:因为当锁释放,事务还没有提交
 */
 
@Aspect
@Component
@Slf4j
public class DistributedLockAspect {
    @Resource
    private RedissonClient redissonClient;
 
    /**
     * @Descreption: 定义切面:以注解为切面
     */
    @Pointcut("@annotation(com.panzhihua.sangeshenbian.annotation.DistributedLock)")
    public void distributedLockAspect() {
    }
 
 
    @Around(value = "distributedLockAspect()")
    public Object doAround(ProceedingJoinPoint pjp) throws Throwable {
 
        //切点所在的类
        MethodSignature methodSignature = (MethodSignature) pjp.getSignature();
        Method method = methodSignature.getMethod();
        //
        DistributedLock annotation = method.getAnnotation(DistributedLock.class);
        String lockName = getLockName(annotation, pjp.getArgs(), method);
        //log.info("lockName:"+lockName);
        RLock lock = redissonClient.getLock(lockName);
        lock.lock();
        try {
            return pjp.proceed();
        } finally {
            if (lock.isLocked() && lock.isHeldByCurrentThread()) {
                //释放锁
                lock.unlock();
            }
        }
    }
 
    /**
     * @Descreption: 获取锁名字,优先获取注解中锁名
     */
    private String getLockName(DistributedLock distributedLock, Object[] args, Method method) {
        //优先获取注解名称
        if (StringUtils.isNotBlank(distributedLock.lockName())) {
            return distributedLock.lockName();
        }
        //根据参数匹配有参数就使用动态参数,没有就使用定义参数
        String lockNamePre = distributedLock.lockNamePre();
        String lockNamePost = distributedLock.lockNamePost();
        String separator = distributedLock.separator();
 
        String preExpression = parseExpression(lockNamePre, method, args);
        String postExpression = parseExpression(lockNamePost, method, args);
        StringBuilder sb = new StringBuilder();
        if (StringUtils.isNotBlank(preExpression)) {
            sb.append(preExpression);
        } else {
            sb.append(lockNamePre);
        }
        sb.append(separator);
        if (StringUtils.isNotBlank(postExpression)) {
            sb.append(postExpression);
        } else {
            sb.append(lockNamePost);
        }
        return sb.toString();
    }
 
    /**
     * el表达式解析
     *
     * @param expressionString 解析值
     * @param method           方法
     * @param args             参数
     * @return
     */
    private String parseExpression(String expressionString, Method method, Object[] args) {
        //获取被拦截方法参数名列表
        LocalVariableTableParameterNameDiscoverer discoverer = new LocalVariableTableParameterNameDiscoverer();
        String[] paramNameArr = discoverer.getParameterNames(method);
        //SPEL解析
        ExpressionParser parser = new SpelExpressionParser();
        StandardEvaluationContext context = new StandardEvaluationContext();
        for (int i = 0; i < Objects.requireNonNull(paramNameArr).length; i++) {
            context.setVariable(paramNameArr[i], args[i]);
        }
        return parser.parseExpression(expressionString).getValue(context, String.class);
    }
 
//    ==========================示例=============================
 
    //    //固定静态参数锁:product_lock
//    @DistributedLock(lockName = "product_lock")
//    @GetMapping(value = "/test1")
//    public void test1() {
//        System.out.println("执行事务");
//    }
//
//    //未匹配到参数,因此仍然是静态参数锁:#param1_#param2
//    @DistributedLock(lockNamePre = "#param1", lockNamePost = "#param2")
//    @GetMapping(value = "/test2")
//    public void test2() {
//        System.out.println("执行事务");
//    }
//
    //匹配到参数,动态参数锁:hello_world
//    @DistributedLock(lockNamePre = "#order", lockNamePost = "#param2")
//    @GetMapping(value = "/test3")
    public void test3(String param1, String param2) {
        System.out.println("执行事务");
    }
}