原文: https://www.cnblogs.com/youzhibing/p/7348337.html
HttpSession是通过Servlet容器创建和管理的,像Tomcat/Jetty都是保存在内存中的。但是我们把应用搭建成分布式的集群,然后利用LVS或Nginx做负载均衡,那么来自同一用户的Http请求将有可能被分发到多个不同的应用中。那问题来了,如何保证不同的应用能够共享同一份session数据呢?最简单的想法,就是把session数据保存到内存以外的一个统一的地方,例如Memcached/Redis等数据库中。那问题又来了,如何替换掉Servlet容器创建和管理的HttpSession的实现呢?
1、利用Servlet容器提供的插件功能,自定义HttpSession的创建和管理策略,并通过配置的方式替换掉默认的策略。这方面其实早就有开源项目了,例如memcached-session-manager(可以参考负载均衡+session共享(memcached-session-manager实现),以及tomcat-redis-session-manager。不过这种方式有个缺点,就是需要耦合Tomcat/Jetty等Servlet容器的代码。
2、设计一个Filter,利用HttpServletRequestWrapper,实现自己的 getSession()方法,接管创建和管理Session数据的工作。spring-session就是通过这样的思路实现的。
参考 spring-session之一 初探 spring-session
本博客不涉及session解释,关于session大家自行去查资料;关于spring-session的相关概念大家可以去spring官网查阅(http://projects.spring.io/spring-session/)。
单机应用
我们先来看下单机应用,应用很简单,就是在session中设置变量,然后获取这些设置的变量进行展示 ,具体代码如下
pom.xml:
web.xml
SessionServlet.java
index.jsp
整个项目结构非常简单,如下如
本地运行起来,效果如下
火狐浏览器与360浏览器代表不同的用户,各自都能获取各自session中的设置的全部变量,很正常,没毛病。
分布式集群应用
单机应用中,session肯定没问题,就存在本地的servlet容器中,那么在分布式集群中会像单机一样正常吗?我们接着往下看
搭建高可用的、实现负载均衡的分布式集群环境可参考nginx实现请求的负载均衡 + keepalived实现nginx的高可用,没搭建的需要先把分布式环境搭建起来
没设置ession共享
应用不变,代码与单机中的完全一致,将代码部署到分布式集群中去
全部运行起来,效果如下
结果是:无论给session设置多少个值,session中的值都获取不到(离我的预期还是有差距,具体什么差距请看我的问题)
spring-session实现session共享
应用有所变化,代码与之前有所不同,具体区别如下(SessionServlet与index.jsp不变)
pom.xml
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app>
<display-name>Archetype Created Web Application</display-name>
<!-- spring-session config -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath*:spring-session.xml</param-value>
</context-param>
<!-- 这个filter 要放在第一个 -->
<filter>
<filter-name>springSessionRepositoryFilter</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>springSessionRepositoryFilter</filter-name>
<url-pattern>/*</url-pattern>
<dispatcher>REQUEST</dispatcher>
<dispatcher>ERROR</dispatcher>
</filter-mapping>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<servlet>
<servlet-name>session</servlet-name>
<servlet-class>com.yzb.lee.servlet.SessionServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>session</servlet-name>
<url-pattern>/session</url-pattern>
</servlet-mapping>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
</web-app>