Pārlūkot izejas kodu

添加分布式锁

caixiaofeng 6 mēneši atpakaļ
vecāks
revīzija
9199224f25

+ 69 - 0
flow-app/src/main/java/com/flow/RedissonLockAspect.java

@@ -0,0 +1,69 @@
+package com.flow;
+
+import com.flow.common.core.exception.BaseException;
+import com.flow.common.redis.annotation.RedissonLock;
+import org.aspectj.lang.ProceedingJoinPoint;
+import org.aspectj.lang.annotation.Around;
+import org.aspectj.lang.annotation.Aspect;
+import org.aspectj.lang.reflect.MethodSignature;
+import org.redisson.api.RLock;
+import org.redisson.api.RedissonClient;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.core.DefaultParameterNameDiscoverer;
+import org.springframework.core.annotation.Order;
+import org.springframework.expression.EvaluationContext;
+import org.springframework.expression.Expression;
+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 org.springframework.util.StringUtils;
+
+import java.lang.reflect.Method;
+import java.util.Optional;
+
+/**
+ * 分布式锁切面
+ */
+@Aspect
+@Component
+@Order(0) // 确保比事务注解先执行,分布式锁在事务外
+public class RedissonLockAspect {
+    private static final ExpressionParser parser = new SpelExpressionParser();
+    private static final DefaultParameterNameDiscoverer parameterNameDiscoverer = new DefaultParameterNameDiscoverer();
+    @Autowired
+    private RedissonClient redissonClient;
+
+    @Around("@annotation(com.flow.common.redis.annotation.RedissonLock)")
+    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
+        Method method = ((MethodSignature) joinPoint.getSignature()).getMethod();
+        RedissonLock redissonLock = method.getAnnotation(RedissonLock.class);
+        // 默认方法限定名+注解排名(可能多个)
+        String prefix = StringUtils.isEmpty(redissonLock.prefixKey()) ? String.format("%s#%s", method.getDeclaringClass(), method.getName()) : redissonLock.prefixKey();
+        // 创建SpringEL表达式上下文
+        EvaluationContext context = new StandardEvaluationContext();
+        String[] params = Optional.ofNullable(parameterNameDiscoverer.getParameterNames(method)).orElse(new String[]{});//解析参数名
+        Object[] args = joinPoint.getArgs();
+        for (int i = 0; i < params.length; i++) {
+            context.setVariable(params[i], args[i]);
+        }
+        // 解析SpringEL表达式
+        Expression expression = parser.parseExpression(redissonLock.key());
+        String key = expression.getValue(context, String.class);
+        // 获取锁
+        String lockName = String.format("%s:%s", prefix, key);
+        RLock lock = redissonClient.getLock(lockName);
+        boolean lockSuccess = lock.tryLock(redissonLock.waitTime(), redissonLock.unit());
+        if (!lockSuccess) {
+            throw new BaseException("请求太频繁了,请稍后再试");
+        }
+        try {
+            // 执行锁内方法
+            return joinPoint.proceed();
+        } finally {
+            if (lock.isLocked() && lock.isHeldByCurrentThread()) {
+                lock.unlock();
+            }
+        }
+    }
+}

+ 10 - 0
flow-common/flow-common-redis-starter/pom.xml

@@ -29,6 +29,16 @@
             <groupId>org.apache.commons</groupId>
             <artifactId>commons-pool2</artifactId>
         </dependency>
+        <!--redisson-->
+        <dependency>
+            <groupId>org.redisson</groupId>
+            <artifactId>redisson-spring-boot-starter</artifactId>
+        </dependency>
+        <!--aop-->
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-aop</artifactId>
+        </dependency>
     </dependencies>
 
 </project>

+ 43 - 0
flow-common/flow-common-redis-starter/src/main/java/com/flow/common/redis/annotation/RedissonLock.java

@@ -0,0 +1,43 @@
+package com.flow.common.redis.annotation;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * 分布式锁注解
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.METHOD)
+public @interface RedissonLock {
+    /**
+     * key的前缀,默认取方法全限定名,除非我们在不同方法上对同一个资源做分布式锁,就自己指定
+     *
+     * @return key的前缀
+     */
+    String prefixKey() default "";
+
+    /**
+     * springEl 表达式
+     *
+     * @return 表达式
+     */
+    String key();
+
+    /**
+     * 等待锁的时间,默认-1,不等待直接失败,redisson默认也是-1
+     *
+     * @return 单位秒
+     */
+    int waitTime() default -1;
+
+    /**
+     * 等待锁的时间单位,默认毫秒
+     *
+     * @return 单位
+     */
+    TimeUnit unit() default TimeUnit.MILLISECONDS;
+
+}

+ 27 - 0
flow-common/flow-common-redis-starter/src/main/java/com/flow/common/redis/configure/RedissonConfigure.java

@@ -0,0 +1,27 @@
+package com.flow.common.redis.configure;
+
+import org.redisson.Redisson;
+import org.redisson.api.RedissonClient;
+import org.redisson.config.Config;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.autoconfigure.data.redis.RedisProperties;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+@Configuration
+public class RedissonConfigure {
+    @Autowired
+    private RedisProperties redisProperties;
+
+    @Bean
+    public RedissonClient redissonClient() {
+        Config config = new Config();
+        config.useSingleServer()
+                .setAddress("redis://" + redisProperties.getHost() + ":" + redisProperties.getPort())
+                .setPassword(redisProperties.getPassword())
+                .setDatabase(redisProperties.getDatabase());
+        return Redisson.create(config);
+    }
+
+
+}

+ 7 - 0
pom.xml

@@ -38,6 +38,7 @@
         <mysql.version>8.0.21</mysql.version>
         <guava.version>33.0.0-jre</guava.version>
         <mybatis.plus.version>3.5.5</mybatis.plus.version>
+        <redisson.version>3.17.1</redisson.version>
     </properties>
 
     <dependencyManagement>
@@ -68,6 +69,12 @@
                 <artifactId>mybatis-plus-boot-starter</artifactId>
                 <version>${mybatis.plus.version}</version>
             </dependency>
+            <!--redisson-->
+            <dependency>
+                <groupId>org.redisson</groupId>
+                <artifactId>redisson-spring-boot-starter</artifactId>
+                <version>${redisson.version}</version>
+            </dependency>
         </dependencies>
     </dependencyManagement>