欢迎光临散文网 会员登陆 & 注册

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

2023-07-09 12:08 作者:鲈鱼懂个der的Java  | 我要投稿

某乎我也写了,如果想直接用代码请直接搜索这个文章标题的某乎

自定义RedissonClient-starter

依赖


<dependencies>  <dependency>    <groupId>org.springframework.boot</groupId>    <artifactId>spring-boot-starter</artifactId>    <version>3.1.0</version>  </dependency>  <dependency>    <groupId>org.springframework.boot</groupId>    <artifactId>spring-boot-autoconfigure</artifactId>    <version>3.1.0</version>  </dependency>  <dependency>    <groupId>org.springframework.boot</groupId>    <artifactId>spring-boot-configuration-processor</artifactId>    <version>3.1.0</version>  </dependency>  <dependency>    <groupId>org.projectlombok</groupId>    <artifactId>lombok</artifactId>    <version>1.18.26</version>  </dependency>  <dependency>    <groupId>org.redisson</groupId>    <artifactId>redisson-spring-boot-starter</artifactId>    <version>3.15.6</version>  </dependency> </dependencies>

基础配置类

ConfigurationProperties装载的时候会在properties/yaml/yml文件中找到前缀位my:caplock之后的配置注解。

请注意:对于装配的时候如果默认会my:caplock之后一级属性的作为配置类的的属性,如果存在my:caplock:lock1:one这种二级属性,此时one会作为lock1(可以看作新类)的一个属性,并且会存在装载配置问题。原因去看springBoot的中文文档,可以去看看springboot的外部配置这一板块

@EnableConfigurationProperties这种和@Value的区别之一是后者可以实现spel表达式的识别,文章下面的自定义注解这种就需要用对应的paser来进行执行语句表达获取value

SPEL:核心技术_Spring 框架文档 (springref.com)


@Setter @Getter @ConfigurationProperties("my.caplock") public class RedisConfig { private String url; private boolean usage; }

配置类


@Configuration(proxyBeanMethods = false) @EnableConfigurationProperties(RedisConfig.class) @Log4j2 public class MyRedisCapLockConfig { @Bean public RedissonClient redissonClient(RedisConfig redisConfig) { if (redisConfig.isUsage()==false){ log.info("不启用redis分布式锁"); return null;        }        Config config = new Config();        config.setTransportMode(TransportMode.NIO);        SingleServerConfig singleServerConfig = config.useSingleServer();        singleServerConfig.setAddress(redisConfig.getUrl()); return Redisson.create(config);    } }

在当前项目的resources\META-INF的文件夹下出创建spring.factories并附上以下内容。


org.springframework.boot.autoconfigure.EnableAutoConfiguration= com.luyu.config.MyRedisCapLockConfig

点击idea下的将对应的maven模块的生命周期进行install保存该项目到本地仓库中


编辑

自定义注解

注意:请在启动类上加上扫描组件的注解,防止spring没有扫描到我们封装的bean,还有开启切面代理


@SpringBootApplication @ComponentScan({"com.luyu"}) @EnableAspectJAutoProxy public class RedisLockApplication {    public static void main(String[] args) {        SpringApplication.run(RedisLockApplication.class, args);    } }


编辑切换为居中

启动项目依赖


<dependencies>    <dependency>        <groupId>org.springframework.boot</groupId>        <artifactId>spring-boot-starter-web</artifactId>    </dependency>    <dependency>        <groupId>com.luyu</groupId>        <artifactId>myRedisStarter</artifactId>        <version>1.1-SNAPSHOT</version>    </dependency>    <dependency>        <groupId>org.springframework.boot</groupId>        <artifactId>spring-boot-starter-test</artifactId>        <scope>test</scope>    </dependency>    <dependency>        <groupId>org.springframework.boot</groupId>        <artifactId>spring-boot-starter-aop</artifactId>    </dependency> </dependencies>


目前我们实现的是一个实现分布式锁功能的注解Lock


import java.lang.annotation.*; /** * @Author luYu * @Date 2023/7/8 13:19 */ @Retention(RetentionPolicy.RUNTIME) //在执行时有效 @Target({ElementType.METHOD}) //允许在方法注解 @Repeatable(Lock.Locks.class) //允许重复注解,前提必须是实现了拥有该目标注解的名字为value的注释数组 @Documented //javadoc 上下文运行 @Inherited  // 继承 public @interface Lock {    // 锁住的key    String lockKey()default "";    // 锁住的时间    int lockTime()default 5;    @Retention(RetentionPolicy.RUNTIME)    @Target(ElementType.METHOD)    @Inherited    @Documented    public @interface Locks {        Lock[] value();    } }

相关切面


@Component @Aspect public class LockAspect { @Resource private RedissonClient redissonClient; @Around("@annotation(com.luyu.redislock.anno.Lock)||@annotation(com.luyu.redislock.anno.Lock.Locks)") public void getvoid(ProceedingJoinPoint joinPoint){        MethodSignature signature = ((MethodSignature) joinPoint.getSignature()); Lock[] annos = signature.getMethod().getAnnotationsByType(Lock.class); getLock(toLock -> {            ArrayList<RLock> rLocks = new ArrayList<>(); for (Lock anno : toLock) {                RLock lock = redissonClient.getLock(anno.lockKey()); try { boolean b = lock.tryLock(anno.lockTime(), TimeUnit.SECONDS); if (!b){ throw new RuntimeException("上锁失败:"+lock.getName());                    }                    rLocks.add(lock); joinPoint.proceed();                } catch (InterruptedException e) {                    e.printStackTrace(); throw new RuntimeException("上锁失败:"+lock.getName());                } catch (Throwable e) { throw new RuntimeException(e);                } finally { unLock(rLocks);                }            }        }, annos);    } public static void getLock(Consumer<Lock[]> consumer, Lock... locks) {        consumer.accept(locks);    } public static void unLock(ArrayList<RLock> rLocks) { if (rLocks.isEmpty()) { return;        } for (RLock rLock : rLocks) { if (rLock.isLocked() && rLock.isHeldByCurrentThread()){                rLock.unlock();                System.out.println("解锁:"+rLock.getName());            }        }    } }


接口


@RestController @RequestMapping("/1") public class LockController { @GetMapping("/ad") @Lock(lockKey = "luyu",lockTime = 4) @Lock(lockKey = "luyu1",lockTime = 3) @SneakyThrows public void  getLock(){ try {            TimeUnit.SECONDS.sleep(2);        } finally {            System.out.println("鲈鱼来了");        }    } }


结果:

因为我在aop重复执行joinPoint.proceed();就输出了两次鲈鱼来了,不要在意细节哈哈。


编辑切换为居中

给大家留了一个坑,@SneakyThrows和很多catach,可以去了解一下。

觉得可以的话点个赞是我持续分享的动力(努力提高我分享的水平)

自定义starter,注解,实现分布式锁的评论 (共 条)

分享到微博请遵守国家法律