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是个工具类,我们想用的是它的静态方法,所以,最好不将其加入容器。本方案为最优方案,个人感觉是最优雅的方案。
工具类
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
package com.example.entity;
public class 123RedissonClient123 {
@Autowirde你懂的
RedissonClient
//这个类中实现自定义方法(即工具雷中的方法,供工具雷调用) public void getLock(String string) {
RedissonClient.get()
System.out.println("RedissonClient#getLock123:" + string); } public void getMap() { System.out.println("RedissonClient#getMap"); } }
Redisson123配置类
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工具类
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;
}
}
启动类
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");
}
}

浙公网安备 33010602011771号