詭異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
啟動類工廠文件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自動裝配機制在開發過程中使用起來很方便,引入相應依賴便能夠開箱即用,對應用上層屏蔽了很多細節,但是一旦出現類似問題而又不報錯時便難以定位,還是我們需要多探究一下框架的細節,也是在進階過程中要掌握的吧。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM