乐趣区

基于SpringBoot-AOP面向切面编程实现Redis分布式锁

基于 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(){// 正常写方法实现}

欢迎关注我的博客,里面有很多精品合集

  • 本文转载注明出处(必须带连接,不能只转文字):字母哥博客。

觉得对您有帮助的话,帮我点赞、分享!您的支持是我不竭的创作动力!。另外,笔者最近一段时间输出了如下的精品内容,期待您的关注。

  • 《手摸手教你学 Spring Boot2.0》
  • 《Spring Security-JWT-OAuth2 一本通》
  • 《实战前后端分离 RBAC 权限管理系统》
  • 《实战 SpringCloud 微服务从青铜到王者》
  • 《VUE 深入浅出系列》
退出移动版