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

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

若是你們沒看過鬆哥以前寫的 Spring Boot 整合 Spring Session,能夠先回顧下:java

第一次踩坑

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

如出一轍的代碼,可是運行就是會出錯,我感受莫名其妙。由於在 Spring Boot 中整合 Spring Session 是一個很是簡單的操做,就幾行 Redis 的配置而已,我在確認了代碼沒問題以後,很快想到了多是版本問題,由於當時 Spring Boot2.1.5 剛剛發佈,我喜歡用最新版。因而我嘗試將 Spring Boot 的版本切換到 2.1.4 ,切換回去以後,果真就 OK了,再次啓動項目又不會報錯了。因而基本肯定這是 Spring Boot 的版本升級帶來的問題。spring

可是當時我並無深究,我覺得就是官方出於安全考慮,讓你在使用 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.四、Spring Boot2.1.6 發現都沒有問題,在使用 Spring Session 的時候都不須要添加 Spring Security 依賴,只有 Spring Boot2.1.5 纔有這個問題。因而我大概明白了,這多是一個 Bug,而不是版本升級的新功能。cookie

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

源頭

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

在 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 乾貨!

原文出處:https://www.cnblogs.com/lenve/p/11351414.html

相關文章
相關標籤/搜索