引用: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是个工具类,我们想用的是它的静态方法,所以,最好不将其加入容器。本方案为最优方案,个人感觉是最优雅的方案。
工具类
package com.example.util; import com.example.entity.RedissonClient; public class RedisLockUtil { private static RedissonClient redissonClient; private static final String PREFIX = "rbac:user:" ; static { System.out.println("RedisLockUtil.static initializer"); RedisLockUtil.redissonClient = ApplicationContextHolder.getContext().getBean(RedissonClient.class); } public static void lock(String name) { RedisLockUtil.redissonClient.getLock(PREFIX + name); } }
RedissonClient
package com.example.entity; public class RedissonClient { public void getLock(String string) { System.out.println("RedissonClient#getLock:" + string); } public void getMap() { System.out.println("RedissonClient#getMap"); } }
Redisson配置类
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.host}") private String host; @Value("${spring.redis.port}") private String port; @Value("${spring.redis.password}") 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(); } }
ApplicationContext工具类
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 ApplicationContextHolder implements ApplicationContextAware { private static ApplicationContext context; @Override public void setApplicationContext(ApplicationContext context) throws BeansException { ApplicationContextHolder.context = context; } public static ApplicationContext getContext() { return context; } }
启动类
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 DemoApplication { @Autowired private RedissonClient redissonClient; public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); RedisLockUtil.lock("Tony"); } }
标签:ApplicationContext,redissonClien,封装,springboot,--,博客,RedissonClient,import,publi From: https://www.cnblogs.com/baicaowei/p/17557557.html