前言
最近在做架构治理时, 发现如下形式的代码
@RequestMapping(value = "/list", method = RequestMethod.POST)
public SomeDto list(HttpServletRequest request,HttpServletResponse response,QueryDto query){
User user= (User) request.getSession().getAttribute("some-key");
...
}
第一反应是, 在一个微服务或者说分布式架构中怎么会通过这种方式来获取用户会话? 但再一想, 如果是读取的服务器Session, 那现在的系统是根本上不了生产的, 甚至是完全不可用的, 既然生产上在稳定运行, 就不会是读的服务器Session
后来翻了翻 Maven 依赖, 发现了个 spring-session, 就是这篇文章的主角
正文
首先需要提一下上面代码中出现的HttpServletRequest, 它源自 Java Servlet API, 现在 Java Servlet API 是Jakarta EE的一部分
Java Servlet API 最早诞生于1997年, 由Sun发布, 但最初的版本并不在 Tomcat 里, 而是作为 Java Web的一部分, 真正开始大规模使用是源自1999年Tomcat项目启动后, 感兴趣的可以去看下 3.x 版本, 也就是2000年发布的源码
在这之后, 出现了大量的以Tomcat为容器的 Java Web 应用, 后来出现的 SpringBoot, 也将 Tomcat 作为默认的Web容器
时间走到2010年之后, 从时代背景来看, 那是互联网巨头之间的竞争到白热化的时期, 以亚马逊为代表的云计算服务也开始铺开, 微服务也是在这个时间段开始流行的, 尤其是 Martin Fowler 在2014年3月发表文章 Microservices 之后
但是微服务也带来了很多问题, 与2000年流行的SOA架构不同, 微服务提倡复制, 而不是复用, 因此出现的数量众多的服务, 导致过去主流的的粘性会话和会话复制方案无法继续使用, 集中式会话存储开始流行
可是多年下来, 已经有大量使用Servlet API访问会话的存量应用, 必须有个办法尽可能实现无缝迁移, 于是spring-session 项目应运而生
Spring Session 最早发布于2015年, 它的设计初衷就是为了无缝地替换和增强原有的 Servlet 会话管理机制, 使得开发者可以在分布式环境中轻松管理会话数据。因此,它默认会拦截和替换 HttpSession 的底层实现,以便将会话管理外部化到 Redis、JDBC等存储中。
但这种做法也带来了显而易见的问题, 就是容易混淆原本 HttpSession 的实现, 就像我在前言中描述的那样。但我们也不能因此对它加以否定, 对于需要改造为分布式的遗留应用来说, 引入它依然是最合适的选择, 但是对于一个新的应用, 个人认为最适合的做法是封装一个会话管理的SDK, 在服务间共享。