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");
    }
  
}

  

posted @   悠然逃之  阅读(3578)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
点击右上角即可分享
微信分享提示