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

如果大家没看过松哥之前写的 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. C语言学习书籍推荐《你必须知道的495个C语言问题》

    萨米特 (Steve summit) (作者), 孙云 (译者), 朱群英 (译者) 下载地址:点我 <你必须知道的495个C语言问题>以问答的形式组织内容,讨论了学习或使用C语言的过程中 ...

  2. php接口数据安全解决方案(二)

    前言 实例演示token签名并创建token 解析token并校验token合法性 类库封装管理jwt实例 前言 JWT是什么 JWT是json web token缩写.它将用户信息加密到token里 ...

  3. Java 源码学习系列(三)——Integer

    Integer 类在对象中包装了一个基本类型 int 的值.Integer 类型的对象包含一个 int 类型的字段. 此外,该类提供了多个方法,能在 int 类型和 String 类型之间互相转换,还 ...

  4. [HNOI2015]菜肴制作 题解(自带口胡证明)

    [HNOI2015]菜肴制作 时间限制: 1 Sec  内存限制: 512 MB 题目描述 知名美食家小 A被邀请至ATM 大酒店,为其品评菜肴. ATM 酒店为小 A 准备了 N 道菜肴,酒店按照为 ...

  5. 前端html+css+JavaScript 需要掌握的单词

    前端html+css+JavaScript 需要掌握的单词   broswer 浏览器(客户端) html 超文本标记语言 css 层叠样式表 javascript 语言名字(类似python/php ...

  6. 全栈工程师知识点汇总——html5(上)

    一.HTML5 1.新特性: 1. 取消了过时的显示效果标记 <font></font> 和 <center></center> ... 2. 新表单元 ...

  7. HBase的优化

    HBase的优化 高可用 在 HBase 中 Hmaster 负责监控 RegionServer 的生命周期,均衡 RegionServer 的负载,如果 Hmaster 挂掉了,那么整个 HBase ...

  8. .NET Core CSharp初级篇 1-6 类的多态与继承

    .NET Core CSharp初级篇 1-6 本节内容为类的多态与继承 简介 终于讲到了面向对象三大特性中的两大特性--继承与多态.通过继承与多态,我们能很好的将类的拓展性发挥到了极致.在下面的内容 ...

  9. python课堂整理19----迭代器和生成器

    一.概念 • 迭代器协议: 对象必须提供一个next方法,执行该方法要么返回迭代中的下一项,要么引起一个stopIteration异常,以终止迭代(只能往后走,不能往前退) • 协议是一种约定,pyt ...

  10. 【经验分享】ASP.NET 的 Page_Load 执行了2次,真的!

    发现问题 这是来自一位网友的提问: 本着求真务实的态度,我打开了 AppBoxPro 项目,本地调试果然发现 Page_Load 进入了两次! 其实在没测试之前,我就有了大概的方向,因为AppBoxP ...