美文网首页分布式
优雅的实现分布式锁控制-自定义注解方式

优雅的实现分布式锁控制-自定义注解方式

作者: yufw | 来源:发表于2020-04-29 16:11 被阅读0次

    自定义注解实现分布式锁实现

    分布式锁的实现基于redisson

    背景

    ​ 很久很久以前,我们的架构都是单体架构,项目也只会部署到一台服务器,基于JVM的 java 同步工具(如ReentrantLcok或synchronized)完全可以保证我们的业务的 原子性;随着微服务,分布式的出现,一个项目会部署到多台服务器(多个JVM),这时候多个服务之间的一系列操作要保证原子性,基于JVM的 java 同步工具(如ReentrantLcok或synchronized)就无能为力了,这时候需要一个针对整个项目(包含所有服务)的一个全局锁来控制业务,这时候分布式锁就应运而生。

    分布式锁的 注意事项
    1. 加锁必须设置过期时间(避免死锁)
    2. 加锁操作必须和设置 过期时间 是原子性操作
      并发操作下 导致加过期时间失败问题(某个线程执行完枷锁操作 未加过期时间 报错终止)
    3. 过期时间 必须保证业务操作 结束
      开始子线程监控 未执行结束 续命(加过期时间)
    4. 必须保证 谁加锁 谁解锁
      防止高并发下 锁失效问题
    java 源码
    @RestController
    public class RedissonLock {
    
        // 分布式锁的 注意事项
        // 1. 加锁必须设置过期时间
        //  (避免死锁)
        // 2. 加锁操作必须和设置 过期时间 是原子性操作
        //  并发操作下 导致加过期时间失败问题(某个线程执行完枷锁操作 未加过期时间 报错终止)
        // 3. 过期时间 必须保证业务操作 结束
        //  开始子线程监控 未执行结束 续命(加过期时间)
        // 4. 必须保证 谁加锁 谁解锁
        //  防止高并发下 锁失效问题
    
        static int r = 0;
    
        @Autowired
        private RedissonClient redissonClient;
    
        @GetMapping("/testLock")
        public int testRedissonLock(@RequestParam boolean isLock) throws InterruptedException {
            RLock rLock = null;
    
    
            int result = 0;
            if(isLock){
                try{// 获取锁
                    rLock = redissonClient.getLock("test1");
    
                    // 上锁
                    rLock.lock(12, TimeUnit.SECONDS);
    
                    result = dobusiness();
                }
                finally {
                    // 解锁
                    rLock.unlock();
                }
    
            } else {
                result = dobusiness();
            }
    
            return result;
    
        }
    
       private int dobusiness() throws InterruptedException {
            ++r;
            TimeUnit.SECONDS.sleep(1);
            System.out.println(r);
            return r;
    
        }
    
    

    转自我的 另一篇博客 https://blog.csdn.net/qq_41692766/article/details/105770758

    使用自定义注解方式实现分布式锁控制

    主要使用技术:
    1. 自定义注解
    2. 切面编程
    1. 自定义注解的使用

    请参考 我的另一篇博客:https://blog.csdn.net/qq_41692766/article/details/105821144(此处不赘述)

    2. 面向切面编程

    请参考 我的另一篇博客:https://blog.csdn.net/qq_41692766/article/details/105821218(此处不赘述)

    进入正题

    准备工作完成,我们直奔主题:

    1. redisson 服务接口

      package com.beauty.beautybase.service;
      
      import org.springframework.stereotype.Service;
      
      import java.util.concurrent.TimeUnit;
      
      /**
       * description Redisson 服务类
       *
       * @author yufw
       * date 2020/4/27 16:40
       */
      
      public interface RedissonService {
      
          /**
           * 无指定时间 加锁
           */
          void lock(String name);
      
          /**
           * 指定时间 加锁
           *
           * @param leaseTime
           * @param unit
           */
          void lock(String name, long leaseTime, TimeUnit unit);
      
      
          boolean tryLock(String name);
      
          boolean tryLock(String name, long time, TimeUnit unit) throws InterruptedException;
      
          boolean isLocked(String name);
      
          void unlock(String name);
      
      }
      
      
    2. 接口实现

      package com.beauty.beautybase.service.Impl;
      
      import com.beauty.beautybase.service.RedissonService;
      import org.redisson.api.RLock;
      import org.redisson.api.RedissonClient;
      import org.springframework.beans.factory.annotation.Autowired;
      import org.springframework.stereotype.Service;
      
      import java.util.concurrent.TimeUnit;
      
      /**
       * description
       *
       * @author yufw
       * date 2020/4/27 16:43
       */
      @Service
      public class RedissonServiceImpl implements RedissonService {
      
          @Autowired
          private RedissonClient redissonClient;
      
          private RLock getLock(String name) {
              RLock lock = redissonClient.getLock(name);
              return lock;
          }
      
          /**
           * 无指定时间 加锁
           */
          @Override
          public void lock(String name) {
              getLock(name).lock();
          }
      
          /**
           * 指定时间 加锁
           *
           * @param leaseTime
           * @param unit
           */
          @Override
          public void lock(String name, long leaseTime, TimeUnit unit) {
      
          }
      
          @Override
          public boolean tryLock(String name) {
              return false;
          }
      
          @Override
          public boolean tryLock(String name, long time, TimeUnit unit) throws InterruptedException {
              return false;
          }
      
          @Override
          public boolean isLocked(String name) {
              return false;
          }
      
          @Override
          public void unlock(String name) {
              getLock(name).unlock();
          }
      }
      
      
    3. 自定义注解

      package com.beauty.beautybase.annotion;
      
      import java.lang.annotation.*;
      import java.util.concurrent.TimeUnit;
      
      
      @Target({ElementType.PARAMETER, ElementType.METHOD})
      @Retention(RetentionPolicy.RUNTIME)
      @Documented
      public @interface DistributeLock {
      
          /**
           * 锁类型
           *
           * @return
           */
          LockType type() default LockType.LOCK;
      
          /**
           * 分布式锁 名称
           *
           * @return
           */
          String name() default "lock";
      
          long leaseTime() default -1;
      
          TimeUnit unit() default TimeUnit.SECONDS;
      
      
      }
      
      
    4. 注解逻辑

      package com.beauty.beautybase.AOP;
      
      
      import com.beauty.beautybase.annotion.DistributeLock;
      import com.beauty.beautybase.annotion.LockType;
      import com.beauty.beautybase.service.RedissonService;
      import org.aspectj.lang.JoinPoint;
      import org.aspectj.lang.annotation.After;
      import org.aspectj.lang.annotation.Aspect;
      import org.aspectj.lang.annotation.Before;
      import org.aspectj.lang.annotation.Pointcut;
      import org.aspectj.lang.reflect.MethodSignature;
      import org.springframework.beans.factory.annotation.Autowired;
      import org.springframework.stereotype.Component;
      
      import java.lang.reflect.Method;
      
      /**
       * description 分布式锁自定义注解 切面
       *
       * @author yufw
       * date 2020/4/27 13:11
       */
      
      @Aspect
      @Component
      public class DistributeLockAop {
      
          @Autowired
          RedissonService redissonService;
      
          /**
           * 切入点
           */
          @Pointcut("@annotation(com.beauty.beautybase.annotion.DistributeLock)")
          public void doBusiness() {
      
          }
      
          /**
           * 前事件
           *
           * @param joinPoint
           */
          @Before("doBusiness()")
          public void doBefore(JoinPoint joinPoint) {
              MethodSignature signature = (MethodSignature) joinPoint.getSignature();
              //获取执行方法
              Method method = signature.getMethod();
              // 获取注解信息
              DistributeLock distributeLock = method.getAnnotation(DistributeLock.class);
      
              if (null != distributeLock) {
                  //获取注解参数值
                  String lockName = distributeLock.name();
                  LockType type = distributeLock.type();
      
                  if (type == LockType.LOCK) {
                      redissonService.lock(lockName);
                      System.out.println("加锁成功");
                  }
      
              }
      
      
          }
      
          /**
           * 后事件
           *
           * @param joinPoint
           */
          @After("doBusiness()")
          public void doAfter(JoinPoint joinPoint) {
      
              MethodSignature signature = (MethodSignature) joinPoint.getSignature();
              //获取执行方法
              Method method = signature.getMethod();
              // 获取注解信息
              DistributeLock distributeLock = method.getAnnotation(DistributeLock.class);
              //获取执行方法名
              String methodName = method.getName();
              //获取方法传递的参数
              Object[] args = joinPoint.getArgs();
      
              if (null != distributeLock) {
                  //获取注解参数值
                  String lockName = distributeLock.name();
      
                  if (null != distributeLock) {
      
                      redissonService.unlock(lockName);
                      System.out.println("解锁成功");
      
                  }
              }
      
          }
      
      
      }
      
      
    5. 测试接口编写

      package com.beauty.beautybase.controller;
      
      import com.beauty.beautybase.annotion.DistributeLock;
      import com.beauty.beautybase.annotion.LockType;
      import org.springframework.web.bind.annotation.GetMapping;
      import org.springframework.web.bind.annotation.RequestMapping;
      import org.springframework.web.bind.annotation.RequestParam;
      import org.springframework.web.bind.annotation.RestController;
      
      import java.util.concurrent.TimeUnit;
      
      /**
       * description
       *
       * @author yufw
       * date 2020/4/28 9:42
       */
      @RestController
      @RequestMapping("/commonBase")
      public class DistributeLockController {
      
      
          @DistributeLock(type = LockType.LOCK, name = "lock")
          @GetMapping("/lock")
          public void testLock() throws Exception {
              System.out.println("test_lock");
              System.out.println("需要加分布式锁的业务逻辑");
              // 此处测试 如果处理 业务逻辑 报错 是否会 解锁(防止死锁)
           //throw new Exception("业务报错");
          }
      
          @GetMapping("/lockTimed")
          public void testLockTimed() {
              System.out.println("test_lockTimed");
      
          }
      
          @GetMapping("/tryLock")
          public void testTryLock() {
      
          }
      
          @GetMapping("tryLockTimed")
          public void testTryLockTimed(@RequestParam int time, @RequestParam TimeUnit unit) {
      
          }
      
      }
      
      
    6. 执行get请求:http://localhost:60030/commonBase/lock

    备注:此功能会持续优化,暂简单实现

    源码地址:https://gitee.com/twelfthLunarMonthFourteen/pub_beauty/tree/hotfix/beauty-base/src/main/java/com/beauty/beautybase

    个人水平有限,如有问题,请各路大神指教留言,评论区讨论,虚心接纳

    如果觉得有帮助,请点赞收藏,谢谢

    相关文章

      网友评论

        本文标题:优雅的实现分布式锁控制-自定义注解方式

        本文链接:https://www.haomeiwen.com/subject/lwhnwhtx.html