诡异bug——Redssion存在时StringRedisTeamplate.opsForValue().setIfAbsent返回为null

Bug背景:


公司SpringBoot项目最近需要用到分布式锁这个东西,分布式锁目前实现有很多种,以Redis来实现的话有StringRedisTeamplate.setIfAbsent,Redssion的RedssionClient以及Gitee上的RedisLock都可以用作分布式锁,实现上差别挺大,项目以前老写法使用下面这个:

文档上介绍是在事务或管道中执行返回为空

@Nullable
Boolean setIfAbsent(K key, V value, long timeout, TimeUnit unit);
--- 而最近又有同事引入了Redision想用Redssion的API来实现分布式锁,但是没有去配置,于是吃螃蟹的我尝试去配置了相关客户端,用了客户端的可重入锁,但是后来诡异的bug发生了,之前用的setIfAbsent方法返回为空了,WTF!!!Debug也很难跟进,里面有大量的回调方法、匿名表达、异步操作,面向搜索引擎编程这次也失灵了,只定位到了是Redssion而没有解决方案,叫人头秃。 * * * ##解决方案 不过最近读了下SpringBoot启动的源码,猜测了下会不会是Boot自动装配的问题,既然是引入了Redssion导致的,那么于是找到了Redssion启动类的代码,就是下面这个文件: ![image](https://img2020.cnblogs.com/blog/1598896/202107/1598896-20210709095706966-893954083.png) 启动类工厂文件spring.factories自动装配的类之一,SpringBoot启动时会加载所有META-INF文件夹下的spring.factories文件,找到要装配的类,RedssionAutoConfiguration会根据@ConditionalOnMissingBean这个注解顺序装配以下几个bean: ``` RedissonClient——>RedissonConnectionFactory——>StringRedisTemplate ```` 问题就显而易见了,如果配置了RedissonClient,没有配置RedissonConnectionFactory,就会以RedssionClient里的连接配置去构建了RedisConnectionFactory,而项目中我又刚好手动去配置了一个RedissonClient,就发生了这么诡异的问题,Redssion底层应该是大量Netty的API,影响了原来的逻辑从而导致了返回为空,当然这个目前还没有验证,后续有机会再深入Debug探讨一下,解决方案下面两个都可以(可以同时配置,任意一个也会生效)。 * * * * 在启动类注解@SpringBootApplication的exclude属性里添加{RedissonAutoConfiguration.class}这个属性,会让SpringBoot根据其他条件自行构建连接池和Redis操作模板,避免StringRedisTeamplate受到RedssionClient的影响。 * 在项目中手动配置RedisConnectionFactory,我配置的是LettucePoolingClientConfiguration这个连接工厂,主要是池大小和Redis实例地址,根据需要自行配置,网上很多案例可供参考,在此就不过多赘述了。 * * * ##总结 SpringBoot自动装配机制在开发过程中使用起来很方便,引入相应依赖便能够开箱即用,对应用上层屏蔽了很多细节,但是一旦出现类似问题而又不报错时便难以定位,还是我们需要多探究一下框架的细节,也是在进阶过程中要掌握的吧。
posted @ 2021-07-09 10:56  Youfail  阅读(2901)  评论(0编辑  收藏  举报