基於SpringBoot AOP面向切面程式設計實現Redis分散式鎖

字母哥部落格發表於2020-07-08

基於SpringBoot AOP面向切面程式設計實現Redis分散式鎖
基於SpringBoot AOP面向切面程式設計實現Redis分散式鎖
基於SpringBoot AOP面向切面程式設計實現Redis分散式鎖

鎖定的目標是確保相互排斥其訪問的資源。實際上,此資源通常是字串。使用redis實現鎖主要是將資源放入redis中並利用其原子性。當其他執行緒訪問時,如果Redis中已經存在此資源,則不允許進行某些後續操作。

Spring Boot通過RedisTemplate使用Redis,在實際使用過程中,分散式鎖可以在封裝後在方法級別使用,這樣使用起來就更方便了,無需到處獲取和釋放鎖。

首先,定義一個註解:

@Target({ElementType.METHOD})  
@Retention(RetentionPolicy.RUNTIME)  
@Inherited  
public @interface RedisLock {

     //鎖定的資源,redis的鍵
    String value() default "default";

    //鎖定保持時間(以毫秒為單位) 
    long keepMills() default 30000;

    //失敗時執行的操作
    LockFailAction action() default LockFailAction.CONTINUE;

    //失敗時執行的操作--列舉
    public enum LockFailAction{  
        GIVEUP,  
        CONTINUE;  
    }
    //重試的間隔
    long sleepMills() default 200;
    //重試次數
    int retryTimes() default 5;  
}

具有分散式鎖的Bean

@Configuration 
@AutoConfigureAfter(RedisAutoConfiguration.class)
public class DistributedLockAutoConfiguration {    
    @Bean    
    @ConditionalOnBean(RedisTemplate.class)    
    public DistributedLock redisDistributedLock(RedisTemplate redisTemplate){       
        return new RedisDistributedLock(redisTemplate);   
    }
}

面向切面程式設計-定義切面

@Aspect  
@Configuration  
@ConditionalOnClass(DistributedLock.class)  
@AutoConfigureAfter(DistributedLockAutoConfiguration.class)  
public class DistributedLockAspectConfiguration {

    private final Logger logger = LoggerFactory.getLogger(DistributedLockAspectConfiguration.class);

    @Autowired  
    private DistributedLock distributedLock;

    @Pointcut("@annotation(com.itopener.lock.redis.spring.boot.autoconfigure.annotations.RedisLock)")  
    private void lockPoint(){

    }

    @Around("lockPoint()")  
    public Object around(ProceedingJoinPoint pjp) throws Throwable{  
        Method method = ((MethodSignature) pjp.getSignature()).getMethod();  
        RedisLock redisLock = method.getAnnotation(RedisLock.class);  
        String key = redisLock.value();  
        if(StringUtils.isEmpty(key)){  
            Object\[\] args = pjp.getArgs();  
            key = Arrays.toString(args);  
        }  
        int retryTimes = redisLock.action().equals(LockFailAction.CONTINUE) ? redisLock.retryTimes() : 0;  
         //獲取分散式鎖 
        boolean lock = distributedLock.lock(key, redisLock.keepMills(), retryTimes, redisLock.sleepMills());  
        if(!lock) {  
            logger.debug("get lock failed : " + key);  
            return null;  
        }

       //執行方法之後,釋放分散式鎖
        logger.debug("get lock success : " + key);  
        try {  
            return pjp.proceed();   //執行方法
        } catch (Exception e) {  
            logger.error("execute locked method occured an exception", e);  
        } finally {  
            boolean releaseResult = distributedLock.releaseLock(key);  //釋放分散式鎖
            logger.debug("release lock :" + key + (releaseResult ?" success" : "failed"));  
        }  
        return null;  
    }  
}

使用方法

  • 進入該方法時,佔用分散式鎖,
  • 方法執行完成時,釋放分散式鎖
  • 使用同一個資源,如your-custom-service-redis-key的多個函式,搶佔同一個鎖。誰搶到誰先執行。
@RedisLock(value="your-custom-service-redis-key")
public void  serviceMethod(){
  //正常寫方法實現
}

歡迎關注我的部落格,裡面有很多精品合集

  • 本文轉載註明出處(必須帶連線,不能只轉文字):字母哥部落格

覺得對您有幫助的話,幫我點贊、分享!您的支援是我不竭的創作動力! 。另外,筆者最近一段時間輸出瞭如下的精品內容,期待您的關注。

相關文章