1. 程式人生 > >Spring Boot 中的同一個 Bug,竟然把我坑了兩次!

Spring Boot 中的同一個 Bug,竟然把我坑了兩次!

真是鬱悶,不過這事又一次提醒我解決問題還是要根治,不能囫圇吞棗,否則相同的問題可能會以不同的形式出現,每次都得花時間去搞。刨根問底,一步到位,再遇到類似問題就可以分分鐘解決了。

如果大家沒看過鬆哥之前寫的 Spring Boot 整合 Spring Session,可以先回顧下:

  • Spring Boot 一個依賴搞定 session 共享,沒有比這更簡單的方案了!

第一次踩坑

事情是這樣的,大概在今年 6 月初的時候,我在專案中使用到了 Session 共享,當時採用的方案就是 Redis+Spring Session。本來這是一個很簡單的問題,我在以前的專案中也用過多次這種方案,早已輕車熟路,但是那次有點不對勁,專案啟動時候報瞭如下錯誤:

一模一樣的程式碼,但是執行就是會出錯,我感覺莫名其妙。因為在 Spring Boot 中整合 Spring Session 是一個非常簡單的操作,就幾行 Redis 的配置而已,我在確認了程式碼沒問題之後,很快想到了可能是版本問題,因為當時 Spring Boot2.1.5 剛剛釋出,我喜歡用最新版。於是我嘗試將 Spring Boot 的版本切換到 2.1.4 ,切換回去之後,果然就 OK了,再次啟動專案又不會報錯了。於是基本確定這是 Spring Boot 的版本升級帶來的問題。

但是當時我並沒有深究,我以為就是官方出於安全考慮,讓你在使用 Redis 時強制加上 Spring Security(因為根據錯誤提示,很容想到加上 Spring Security 依賴),加上 Spring Security 依賴之後,果然就沒有問題了,我也沒有多想,這件事就這樣過了。​

第二次踩坑

前兩天我在給星球上的小夥伴錄製 Spring Boot 視訊的時候,採用了 Spring Boot 最新版 2.1.7,也是 Spring Session,但是在建立專案的時候,忘記新增 Spring Security 依賴了(第一次踩坑之後,我每次用 Spring Session 都會自覺的加上 Spring Security 依賴),執行的時候竟然沒報錯!我就鬱悶了。

於是我去試了 Spring Boot2.1.4、Spring Boot2.1.6 發現都沒有問題,在使用 Spring Session 的時候都不需要新增 Spring Security 依賴,只有 Spring Boot2.1.5 才有這個問題。於是我大概明白了,這可能是一個 Bug,而不是版本升級的新功能。

這一次,那我就打算追究一下問題的根源。

源頭

要追究問題的源頭,我們當然得從 Spring Session 的自動化配置類開始。

在 Spring Boot2.1.5 的 org.springframework.boot.autoconfigure.session.SessionAutoConfiguration 類中,我看到如下原始碼:

@Bean
@Conditional(DefaultCookieSerializerCondition.class)
public DefaultCookieSerializer cookieSerializer(ServerProperties serverProperties,
        ObjectProvider<SpringSessionRememberMeServices> springSessionRememberMeServices) {
    //.....
    map.from(cookie::getMaxAge).to((maxAge) -> cookieSerializer
            .setCookieMaxAge((int) maxAge.getSeconds()));
    springSessionRememberMeServices.ifAvailable((
            rememberMeServices) -> cookieSerializer.setRememberMeRequestAttribute(
                    SpringSessionRememberMeServices.REMEMBER_ME_LOGIN_ATTR));
    return cookieSerializer;
}

從這一段原始碼中我們可以看到,這裡使用到了 SpringSessionRememberMeServices ,而這個類中則用到 Spring Security 中相關的類。因此,如果不引入 Spring Security 就會報錯。

我們再來看看 Spring Boot2.1.6 中 org.springframework.boot.autoconfigure.session.SessionAutoConfiguration 類的原始碼,如下:

@Bean
@Conditional(DefaultCookieSerializerCondition.class)
public DefaultCookieSerializer cookieSerializer(ServerProperties serverProperties) {
    //...
    map.from(cookie::getMaxAge).to((maxAge) -> cookieSerializer.setCookieMaxAge((int) maxAge.getSeconds()));
    if (ClassUtils.isPresent(REMEMBER_ME_SERVICES_CLASS, getClass().getClassLoader())) {
        new RememberMeServicesCookieSerializerCustomizer().apply(cookieSerializer);
    }
    return cookieSerializer;
}

可以看到,在 Spring Boot2.1.6 中,這個問題已經得到修復。這裡就沒有 2.1.5 那麼衝動了,上來了先用 ClassUtils.isPresent 方法判斷了下 REMEMBER_ME_SERVICES_CLASS(org.springframework.security.web.authentication.RememberMeServices) 是否存在,存在的話,才有後面的操作。

至此,這個問題就總算弄懂了。

結語

大家平時遇到問題,如果專案不是很趕的話,可以留意多想想,多追究一下原因,說不定你會有很多意外的收穫。我這次就是一個活生生的例子,一開始沒多想,後來又發現不對勁,前前後後一折騰,反而又多浪費了一些時間。

關注公眾號【江南一點雨】,專注於 Spring Boot+微服務以及前後端分離等全棧技術,定期視訊教程分享,關注後回覆 Java ,領取鬆哥為你精心準備的 Java 乾貨!

相關推薦

Spring Boot 同一個 Bug竟然

真是鬱悶,不過這事又一次提醒我解決問題還是要根治,不能囫圇吞棗,否則相同的問題可能會以不同的形式出現,每次都得花時間去搞。刨根問底,一步到位,再遇到類似問題就可以分分鐘解決了。 如果大家沒看過鬆哥之前寫的 Spring Boot 整合 Spring Session,可以先回顧下: Spring Boot 一

解決Spring boot使用GsonSwagger2 api-docs無法正常顯示json問題

由於專案中存在自定義型別,而Jackson的序列化與反序列化又不太會玩,轉而使用Gson,由於有生成Restful API文件的需求,使用Swagger2,最終api-docs無法正常顯示(使用Jack

Spring boot引數注入@Value失效以及解決方案

問題 專案中我們都要要儘量避免將引數直接寫程序序裡,這樣一旦需要需要修改配置,我們可以只需要在配置檔案裡做修改,而不必在程式裡找,這樣可以避免很多錯誤,個人專案可能不會注意這一點,但是需要上線釋出的專案,Configure配置檔案就顯得非常重要!現在很多公司其

Spring Boot(三): 在Spring Boot使用log4j2讓你的console端豐富起來。

maven依賴 <dependency> <groupId>org.springframework.boot</groupId>

徒手擼一個 Spring Boot 的 Starter 解密自動化配置黑魔法

我們使用 Spring Boot,基本上都是沉醉在它 Stater 的方便之中。Starter 為我們帶來了眾多的自動化配置,有了這些自動化配置,我們可以不費吹灰之力就能搭建一個生產級開發環境,有的小夥伴會覺得這個 Starter 好神奇呀!其實 Starter 也都是 Spring + SpringMVC

RabbitMQ從在阿里雲安裝到在spring boot如何使用這一篇就可以

//某個服務的具體情況 ps -ef | grep XXX //殺死程序 kill -9 程序ID,第一個 //檢視記憶體 free或者top //檢視磁碟使用情況 df -l //尋找檔案 find -name xxx //檢視埠使用情況 netstat -an |

如何在 Spring/Spring Boot 做引數校驗?你需要解的都在這裡

本文為作者原創,如需轉載請在文首著名地址,公眾號轉載請申請開白。 springboot-guide : 適合新手入門以及有經驗的開發人員查閱的 Spring Boot 教程(業餘時間維護中,歡迎一起維護)。 資料的校驗的重要性就不用說了,即使在前端對資料進行校驗的情況下,我們還是要對傳入後端的資料再進行一

同一個Spring AOP的一天踩

[GitHub 18k Star 的Java工程師成神之路,不來了解一下嗎!](https://github.com/hollischuang/toBeTopJavaer) [GitHub 18k Star 的Java工程師成神之路,真的不來了解一下嗎!](https://github.com/hollis

經典演算法題1:找出陣列只出現一的數字其它數字都出現

題目:一個整型數組裡除了一個數字之外,其它的數字都出現了兩次。請寫程式找出這個只出現一次的數字。要求時間複雜度是O(n),空間複雜度是O(1)。 分析:由於題目要求時間複雜度為O(n),所以先排序然後比較相鄰數字是否相同的思路被排除。             空間複雜度是O

鄭乾金融:僅僅做半年汽車眾籌卻讓一套房

鄭乾金融|眾籌理財|汽車眾籌|眾籌融資|二手車眾籌 真的很猶豫要不要分享自己的故事,寫出來吧,肯定有很多人要噴我,說我裝;不寫吧,我覺得我的經歷非常值得跟大家分享,能夠給很多想投資的朋友一些指導。猶豫再三,決定還是寫出來! 我的

NSNotificationCenter+RACSupport

熟悉RAC的,應該都知道它本身針對iOS系統類提供了許多類目用於增加方法,方便使用。但是,今天在使用NSNotificationCenter+RACSupport的時候遇到了坑,接下來便分享出來。 下面用到的完成測試用例在這裡。 首頁,建立兩個頁面A、B,然後A訂閱通知,B傳送通知,

Spring Boot 配置定時任務實現多線程操作

pre log pri http code china 部分 多線程操作 .net 參考的代碼部分 https://git.oschina.net/jokerForTao/spring_boot_schedule 一目了然!Spring Boot 中配置定時任務,實現

使用Logstash同步數據至ElasticsearchSpring Boot集成Elasticsearch實現搜索

開啟 stash auto -a zab rest driver tid list 安裝logstash、同步數據至ElasticSearch 為什麽使用logstash來同步,CSDN上有一篇文章簡要的分析了以下幾種同步工具的優缺點:https://blog.csdn.

spring bootsecurity安全退出如何跳轉指定頁面iframe與安全器相容性問題

分享一下這這次專案中自己學到的一些東西(還沒學完,技術很菜,寫的有問題希望大家指出來,希望大家可以一起學習,一起努力)       在WebSecurityConfig中配置:        http.log

spring Boot 上傳檔案10天后不能上傳的bug

起因           公司研發人員 部署服務在阿里雲 ecs 伺服器; 上傳檔案過1周左右檔案自動丟失; 排查思路:     (1).查詢tomcat 啟動日誌出現如下資訊:   

spring boot 1.x配置不斷完善

spring boot是典型的約定大於配置,那麼很有必要對在開發過程中這些配置做統一的新增記錄,以免用到的時候到處搜尋,網上的東西又良莠不齊。 server.port=8880   微服務註冊中心,yml檔案 server: port: 8761 # 服務在啟動時,會把自

spring boot返回date為EEE MMM dd HH:mm:ss z yyyy(Fri Oct 26 00:00:00 CST 2018)轉換為 yyyy-MM-dd HH:mm:ss

問題:資料庫中日期型別為timestamp,實體類中定義為date,返回給到前端時變為了EEE MMM dd HH:mm:ss z yyyy(Fri Oct 26 00:00:00 CST 2018)格式,而我們需要的是yyyy-MM-dd HH:mm:ss。 解決方式: 在實體類定義中,定

Spring Boot使用thymeleaf以及各種取值判斷選擇擷取等方式

Spring Boot中使用thymeleaf Spring Boot支援FreeMarker、Groovy、Thymeleaf和Mustache四種模板解析引擎,官方推薦使用Thymeleaf。 spring-boot-starter-thymeleaf 在Spring B

spring bootspring security實現單點登入傳統模式(一)

單點登入是什麼? 一個系統中可能會引用別的很多系統。單點登入就是解決,一次登入,就可以訪問所有的系統。 每次瀏覽器向一個域名傳送http請求,會去查詢域名的cookie資訊拼接到http的header中傳送到伺服器。 cookie不能跨域。這個域是瀏覽器請求的域名,哪怕他們都是訪問一

使用Eclipse除錯Spring boot工程的時候總是會直接進入SilentExitExceptionHandler

使用Eclipse除錯Spring boot工程的時候,總是會直接進入SilentExitExceptionHandler中,無法正常的debug,嚴重影響效率,在部落格上看到了別人的參考方案,在此記憶一下,方便檢視。     解決方案:Window-->Pre