springboot中解决redissonClient无法注入,redissonClient分布式锁
引用:https://blog.csdn.net/feiying0canglang/article/details/120464693
问题来源
前几天遇到一个循环依赖问题,是RedissonClient这个bean引起的。RedissonClient是由一个配置类(@Configuration注解的类)提供的,这配置类在初始化时(@PostConstruct注解的方法中)去获取RedissonClient这个bean。我在自动注入(@Autowired)RedissonClient时发现报循环依赖异常,应用无法启动。
为什么配置类要在实例化时获取自己管理的bean呢?因为代码的作者是要把这个配置类作为工具类,这个工具类要用到这个bean。这个工具类是作为Redis分布式锁用的,用到RedissonClient锁相关方法,而我想注入RedissonClient,使用它读写Redis的方法。
本文介绍这个问题是如何引起的,以及如何解决。
题外话
刚遇到这个问题时,我其实有点窃喜的。原因是:这个问题我知道快速解决的方案,也想通过这个问题来深入了解循环依赖的原理。
快速解决的方案是:不进行自动注入,使用时再使用ApplicationContext来获取,对应这篇博客:Spring--ApplicationContext--使用/教程/原理_IT利刃出鞘的博客-CSDN博客
我之前写过关于循环依赖的博客,对循环依赖也算是比较熟悉了,我感觉我能以比较优雅的方式来解决这个问题。循环依赖相关博客为:
Spring--循环依赖--解决方案--实例_IT利刃出鞘的博客-CSDN博客_IT利刃出鞘的博客-CSDN博客
Spring--原理--循环依赖--@Autowired_IT利刃出鞘的博客-CSDN博客
这也说明了写博客的重要性,有问题直接找就行,自己实测过的代码,用起来绝对放心。
————————————————
版权声明:本文为CSDN博主「IT利刃出鞘」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/feiying0canglang/article/details/120464693
本处为了简单起见不引用RedisClient依赖,自己写一个简单的类进行示例。
方案1:不自动注入
SpringBoot启动时会扫描所有被@Component注解的bean,然后去扫描这个bean里边的字段,如果它有@Autowired注解,那就从Spring容器中找它然后将引用地址赋值给这个字段,如果找不到则去实例化它。
本文的使用@Autowired注入RedissonClient就是这样,启动时去实例化它导致的失败。
所以思路很简单,我不自动注入,我使用的时候再获取,这样启动时就不会去实例化它。获取的方法为:使用ApplicationContext。想详细了解ApplicationContext的可以见此文。
————————————————
版权声明:本文为CSDN博主「IT利刃出鞘」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/feiying0canglang/article/details/120464693
方案2:延迟注入
Spring有延迟注入的方法,使用的时候再去实例化这个bean,而不是启动时就实例化,见这里:Spring(SpringBoot)--延迟加载(@Lazy注解等)--使用/原理_IT利刃出鞘的博客-CSDN博客_service 延迟加载
方案3:用方法获得bean
此方法更简单了,对代码的改动最小。
方案4:bean放到外部管理
对于这个RedisLockUtil配置类,它同时也是工具类,它用到了RedissonClient的锁功能,其实RedissonClient的其他读写Redis的方法也巨好用,就像操作JDK中的List、Set、Map一样,RedissonClient实际是实现了JDK中的List、Set、Map,所以使用RedissonClient操作Redis就像我们操作JDK的List、Set、Map一样,超级便利。基于此,我把RedissonClient的配置单独拿出来。
————————————————
版权声明:本文为CSDN博主「IT利刃出鞘」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/feiying0canglang/article/details/120464693
方案5:工具类不加入容器(推荐)
思考一下:RedisLockUtil是个工具类,我们想用的是它的静态方法,所以,最好不将其加入容器。本方案为最优方案,个人感觉是最优雅的方案。
工具类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | package com.example.util; import com.example.entity.RedissonClient; public class 123RedisLockUtil { private static RedissonClient redissonClient; private static final String PREFIX = "rbac:user123:" ; //初始化加载 static { System.out.println( "RedisLockUtil.static initializer123" ); RedisLockUtil.redissonClient = ApplicationContextHolder.getContext().getBean(RedissonClient. class ); } //工具雷中的方法,具体调用自定义实体雷中的,自定义方法 public static void lock(String name) { RedisLockUtil.redissonClient.getLock(PREFIX + name123); } } |
RedissonClient123
1 2 3 4 | package com.example.entity; public class 123RedissonClient123 { @Autowirde 你懂的<br>RedissonClient<br> //这个类中实现自定义方法(即工具雷中的方法,供工具雷调用) public void getLock(String string) {RedissonClient.get()System.out.println( "RedissonClient#getLock123:" + string); } public void getMap() { System.out.println( "RedissonClient#getMap" ); } } |
Redisson123配置类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | package com.example.config; import com.example.entity.RedissonClient; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class RedissonConfig { @Value ( "${spring.redis.host123}" ) private String host; @Value ( "${spring.redis.port123}" ) private String port; @Value ( "${spring.redis.password123}" ) private String password; @Bean public RedissonClient getRedisson() { Config config = new Config(); SingleServerConfig singleServerConfig = config.useSingleServer(); singleServerConfig.setAddress( "redis://" + host + ":" + port).setPassword(password); return Redisson.create(config); } @Bean public RedissonClient getRedissonClient() { return new RedissonClient(); } } |
ApplicationContext123工具类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | package com.example.util; import org.springframework.beans.BeansException; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; import org.springframework.stereotype.Component; @Component public class 123ApplicationContextHolder implements ApplicationContextAware { private static ApplicationContext context; @Override public void 123setApplicationContext(ApplicationContext context) throws BeansException { ApplicationContextHolder.context = context; } public static 123ApplicationContext getContext() { return context; } } |
启动类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | package com.example; import com.example.entity.RedissonClient; import com.example.util.RedisLockUtil; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class 123DemoApplication { @Autowired private RedissonClient redissonClient; public static void main(String[] args) { SpringApplication.run(DemoApplication. class , args); RedisLockUtil.lock( "Tony1123" ); } } |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构