Implémentez des verrous distribués à l'aide d'annotations personnalisées basées sur Redisson

Implémentez des verrous distribués à l'aide d'annotations personnalisées basées sur Redisson

1. Principe de mise en œuvre

  1. Basé sur Redisson;

  2. Implémentation d'une annotation, le code est le suivant :

    @Target({
          
          ElementType.METHOD, ElementType.TYPE})
    @Retention(RetentionPolicy.RUNTIME)
    public @interface DistributedLock {
          
          
    
        long TEN_THOUSAND = 10000L;
    
        long EIGHT_THOUSAND = 8000L;
    
        /**
         * 锁的名称
         */
        String name() default "";
    
        /**
         * 锁的过期时间,单位ms,默认8000
         */
        long expireMillis() default EIGHT_THOUSAND;
    
        /**
         * 获取锁的超时时间,单位ms,默认10000
         */
        long acquireTimeoutMillis() default TEN_THOUSAND;
    
    }
    
  3. Implémentation d'un aspect. Lorsqu'une méthode utilise l'annotation @DistributedLock, elle acquerra le verrou distribué avant d'exécuter la méthode. le code s'affiche comme ci-dessous :

    @Aspect
    @Component
    @Slf4j
    public class DistributedLockAspect {
          
          
    
        @Resource
        private RedissonClient redissonClient;
    
        @Pointcut("@annotation(com.xxx.xxx.xxx.xxx.DistributedLock)")
        public void myPointcut() {
          
          
    
        }
    
        @Around(value = "myPointcut()")
        public Object around(ProceedingJoinPoint pjp) throws Throwable {
          
          
            DistributedLock distributedLock = getAnnotation(pjp);
            String lockName = resolveKey(distributedLock.name(), pjp);
            RLock lock = redissonClient.getLock(lockName);
            try {
          
          
    
                Stopwatch stopwatch = Stopwatch.createStarted();
                boolean success = lock.tryLock(distributedLock.acquireTimeoutMillis(), distributedLock.expireMillis(),
                    TimeUnit.MILLISECONDS);
                LOGGER.info("tryLock, result:{}, cost:{}", success, stopwatch.stop().elapsed(TimeUnit.MILLISECONDS));
                if (success) {
          
          
                    LOGGER.info("获取锁成功,lockName={}", lockName);
                } else {
          
          
                    LOGGER.info("获取锁失败,lockName={}", lockName);
                }
                return pjp.proceed();
            } finally {
          
          
                if (lock.isHeldByCurrentThread()) {
          
          
                    lock.unlock();
                    LOGGER.info("释放锁成功,lockName={}", lockName);
                }
            }
        }
    
        private DistributedLock getAnnotation(ProceedingJoinPoint pjp) {
          
          
            MethodSignature methodSignature = (MethodSignature) pjp.getSignature();
            return methodSignature.getMethod().getAnnotation(DistributedLock.class);
        }
    
        private String resolveKey(String key, ProceedingJoinPoint pjp) {
          
          
            if (StringUtils.isBlank(key)) {
          
          
                return pjp.getSignature().toLongString();
            } else {
          
          
                StandardEvaluationContext context = new StandardEvaluationContext();
                Object[] args = pjp.getArgs();
                MethodSignature methodSignature = (MethodSignature) pjp.getSignature();
                String[] params = methodSignature.getParameterNames();
                for (int i = 0; i < params.length; i++) {
          
          
                    context.setVariable(params[i], args[i]);
                }
                return new SpelExpressionParser().parseExpression(key).getValue(context, String.class);
            }
        }
    }
    
  4. Essentiellement, il s’agit lock.tryLock(distributedLock.acquireTimeoutMillis(),distributedLock.expireMillis(),TimeUnit.MILLISECONDS);d’un verrou distribué acquis via ;

  5. Parce que distributedLock.acquireTimeoutMillis()ce n'est pas le cas 0, si un thread n'obtient pas le verrou, il continuera à attendre pendant le temps spécifié et continuera à essayer d'acquérir le verrou pendant la période ; la valeur par défaut actuelle est celle-ci, puisqu'il ne le prend généralement distributedLock.acquireTimeoutMillis()pas 10s. long pour exécuter la logique métier, un thread n'attend normalement pas longtemps 10s, ce qui est principalement utilisé pour le résultat net ;
    le délai d'expiration du verrou est distributedLock.expireMillis()actuellement la valeur par défaut 8s, car l'exécution de l'activité ne prend généralement pas autant de temps Logique, donc dans des circonstances normales, un thread ne tiendra pas le verrou pendant une longue période 8s, principalement pour le résultat final ;
    utiliser pour SPELobtenirlockName ;

2. Comment utiliser

  1. Sur une méthode de n’importe quel calque, ajoutez @DistributedLock(name = "XXX")即可对"XXX"un verrou ;

  2. Exemple 1:

    @DistributedLock(name = "'get'+#codes")
    public void get(String codes) {
          
          
        List<String> codeList = Arrays.stream(orgCodes.split(",")).collect(Collectors.toList());
        ext(codeList);
    }
    

    Si le paramètre d'entrée de la méthode ci-dessus codesest 111,222,333,444, alors SPELcelui analysé lockNameest get111,222,333,444;

  3. Exemple 2 :

    @DistributedLock(name = "'attendance_info'+#attendanceInfo.orderId+#attendanceInfo.date")
    public Integer insertDedup(ConstructionAttendanceInfo attendanceInfo, AtomicInteger dmlType) {
          
          
    	// 此处省略
    	return 0;
    }
    

    Si le paramètre d'entrée de la méthode ci-dessus attendanceInfoest orderId, aaaest date, 2023-08-01alors celui SPELanalysé lockNameest attendance_infoaaa2023-08-01;

3. Précautions

Lorsqu'il est utilisé, nameil doit être spécifié name = "'<方法名/唯一标识名>'+#<入参/入参的某个字段>"pour éviter que différentes méthodes ne génèrent le même lockName;

Je suppose que tu aimes

Origine blog.csdn.net/itigoitie/article/details/132047955
conseillé
Classement