真是郁闷,不过这事又一次提醒我解决问题还是要根治,不能囫囵吞枣,否则相同的问题可能会以不同的形式出现,每次都得花时间去搞。刨根问底,一步到位,再遇到类似问题就可以分分钟解决了。

如果大家没看过松哥之前写的 Spring Boot 整合 Spring 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,竟然把我坑了两次!的更多相关文章

  1. spring boot(三):Spring Boot中Redis的使用

    spring boot对常用的数据库支持外,对nosql 数据库也进行了封装自动化. redis介绍 Redis是目前业界使用最广泛的内存数据存储.相比memcached,Redis支持更丰富的数据结 ...

  2. Spring Boot 中的静态资源到底要放在哪里?

    当我们使用 SpringMVC 框架时,静态资源会被拦截,需要添加额外配置,之前老有小伙伴在微信上问松哥Spring Boot 中的静态资源加载问题:"松哥,我的HTML页面好像没有样式?& ...

  3. Spring Boot:Spring Boot 中 Redis 的使用

    Redis 介绍 Redis 是目前业界使用最广泛的内存数据存储.相比 Memcached,Redis 支持更丰富的数据结构,例如 hashes, lists, sets 等,同时支持数据持久化.除此 ...

  4. (转)Spring Boot(三):Spring Boot 中 Redis 的使用

    http://www.ityouknow.com/springboot/2016/03/06/spring-boot-redis.html Spring Boot 对常用的数据库支持外,对 Nosql ...

  5. Spring Boot 中配置文件application.properties使用

    一.配置文档配置项的调用(application.properties可放在resources,或者resources下的config文件夹里) package com.my.study.contro ...

  6. 学习Spring Boot:(二十三)Spring Boot 中使用 Docker

    前言 简单的学习下怎么在 Spring Boot 中使用 Docker 进行构建,发布一个镜像,现在我们通过远程的 docker api 构建镜像,运行容器,发布镜像等操作. 这里只介绍两种方式: 远 ...

  7. Spring Boot(三):Spring Boot 中 Redis 的使用

    Spring Boot 对常用的数据库支持外,对 Nosql 数据库也进行了封装自动化. Redis 介绍 Redis 是目前业界使用最广泛的内存数据存储.相比 Memcached,Redis 支持更 ...

  8. Spring Boot中使用EhCache实现缓存支持

     SpringBoot提供数据缓存功能的支持,提供了一系列的自动化配置,使我们可以非常方便的使用缓存.,相信非常多人已经用过cache了.因为数据库的IO瓶颈.一般情况下我们都会引入非常多的缓存策略, ...

  9. Spring Boot中实现logback多环境日志配置

    在Spring Boot中,可以在logback.xml中的springProfile标签中定义多个环境logback.xml: <springProfile name="produc ...

随机推荐

  1. Oracle数据库---序列、索引、同义词

    --创建序列create sequence deptno_seqstart with 50increment by 10maxvalue 70cache 3; --为了方便演示,创建了一个和dept表 ...

  2. 网络下载器 迅雷大众版 v7.9.42.5050 精简绿色版

    下载地址:点我 基本介绍 迅雷大众版是一款采用了先进的超线程技术基于网格原理,能够将存在于第三方服务器和计算机上的数据文件进行有效整合,通过这种先进的超线程技术,用户能够以更快的速度从这些第三方节点平 ...

  3. spring boot admin抛出"status":401,"error":"Unauthorized"异常

    打开spring boot admin的监控平台发现其监控的服务明细打开均抛出异常: Error: {"timestamp":1502749349892,"status& ...

  4. Spring Cloud Alibaba | Nacos配置管理

    目录 Spring Cloud Alibaba | Nacos配置管理 1. pom.xml 项目依赖 2. 在 bootstrap.properties 中配置 Nacos server 的地址和应 ...

  5. 006.SQLServer AlwaysOn可用性组高可用部署

    一 数据库镜像部署准备 1.1 数据库镜像支持 有关对 SQL Server 2012 中的数据库镜像的支持的信息,请参考:https://docs.microsoft.com/zh-cn/previ ...

  6. Java 将Word转为PDF、PNG、SVG、RTF、XPS、TXT、XML

    同一文档在不同的编译或阅读环境中,需要使用特定的文档格式来打开,通常需要通过转换文档格式的方式来实现.下面将介绍在Java程序中如何来转换Word文档为其他几种常见文档格式,如PDF.图片png.sv ...

  7. linux服务器无telnet等测试工具,测试http+json服务连通性

    1. 问题描述: 1.公司内部服务器需要通过http接口方式访问另一公司内部接口服务器. 2.申请信息安全开通访问权限,但是只能开通到服务器+端口号,例如:192.168.1:8080,无ping权限 ...

  8. 彻底搞清楚c#中的委托和事件

    一.什么是委托呢? 听着名字挺抽象,确实不好理解.面试官最喜欢考察这个,而且更喜欢问:“委托和事件有何异同?”.如果对一些知识点没有想明白,那么很容易被绕进去.研究任何事物,我们不妨从它的定义开始,委 ...

  9. linux_硬链接和软链接区别

    硬链接有点类似于复制的概念.    ln 源文件 目的文件    ln不加-s,则默认是硬链接.例如,ln script script-hard,ls命令显示,script*显示硬链接有两个.我任意删 ...

  10. 《ElasticSearch6.x实战教程》之复杂搜索、Java客户端(下)

    第八章-复杂搜索 黑夜给了我黑色的眼睛,我却用它寻找光明. 经过了解简单的API和简单搜索,已经基本上能应付大部分的使用场景.可是非关系型数据库数据的文档数据往往又多又杂,各种各样冗余的字段,组成了一 ...