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

相关文章
相关标签/搜索