Spring - Spring Session Redis 共享

简介: Spring - Spring Session Redis 共享

前言

Web开发中session一直都是做分布式集群应用时需要解决的一个难题,前面写了tomcat服务器集群的文章,那么集群中怎么实现session共享呢?

让我们回顾一下,Tomcat集群搭建(APACHE+MOD_JK+TOMCAT配置)的session共享是直接通过tomcat自带的复制功能,即访问其中一台tomcat服务器就会在其他配置好的tomcat服务器上各复制一份session,这样的session共享可能会存在一定的延迟,同时若并发量一大的话也会有网络风暴的风险;而Tomcat集群搭建(nginx+tomcat+redis)的session共享是通过第三方redis来存储session来实现的,这种方式以前比较流行,但是这种也是需要依赖于tomcat(需要修改tomcat的context.xml的配置),而且现在官方也没去更新tomcat-redis-session-manager的jar包了(仍然停留在支持tomcat7上,一些自己修改的jar包除外)。

本文我要说的session共享,就是独立于servlet容器、session存储在第三方存储容器redis的spring session。它不用担心并发量大时的网络风暴;不用担心换容器运行时,又需要各种各样的配置;不用担心servlet容器(即这里的tomcat)停止服务了,session就不存在了,用户又得重新登陆的麻烦。因为spring session的实现是在项目的配置,以及代码中的。

在开始之前,让我们先了解一下spring session实现session共享,以及在spring框架中实现的原理。

spring session通过redis来实现多个服务器间的session共享的原理,其实就是将session独立出来不依赖原来的web容器,而是存放到与web容器没有耦合关系的redis容器中,这样即使是任何一台web容器挂了,也不会影响到其中的session,如下图所示:

image.pngspring session在spring框架中的实现原理,其实就是在请求request上通过DelegatingFilterProxy代理过滤器封装了一层,将原来存储在容器缓存的session变成存储在redis的session,所以在web.xml中的此filter必须得是在所有filter的前面。具体的web容器加载过程,如下图所示:

image.png

准备工作

这里的准备工作有几点,redis存储容器、spring框架的jar包(需要在spring框架的环境下)和spring session的相关jar包。其中redis存储容器,我就不多说了,网上有很多redis的安装教程。


spring框架的jar包

若你的项目原本就有spring框架的,忽略此准备工作。

commons-logging选择1.2版本:http://commons.apache.org/proper/commons-logging/download_logging.cgi

spring-aop选择5.0.8版本:http://www.mvnrepository.com/artifact/org.springframework/spring-aop

spring-beans选择5.0.8版本:http://mvnrepository.com/artifact/org.springframework/spring-beans

spring-context选择5.0.8版本:http://mvnrepository.com/artifact/org.springframework/spring-context

spring-core选择5.0.8版本:http://mvnrepository.com/artifact/org.springframework/spring-core

spring-expression选择5.0.8版本:http://mvnrepository.com/artifact/org.springframework/spring-expression

spring-web选择5.0.8版本:http://mvnrepository.com/artifact/org.springframework/spring-web

spring-webmvc选择5.0.8版本:http://www.mvnrepository.com/artifact/org.springframework/spring-webmvc

spring-tx选择5.0.8版本:http://mvnrepository.com/artifact/org.springframework/spring-tx

spring session的相关jar包

commons-pool2选择2.6.0版本:http://commons.apache.org/proper/commons-pool/download_pool.cgi

jedis选择2.9.0版本:http://central.maven.org/maven2/redis/clients/jedis/

spring-data-commons选择2.0.9版本:https://repo.spring.io/libs-release/org/springframework/data/spring-data-commons/

spring-data-redis选择2.0.9版本:https://repo.spring.io/libs-release/org/springframework/data/spring-data-redis/

spring-session-core选择2.0.5版本:http://mvnrepository.com/artifact/org.springframework.session/spring-session-core

spring-session-data-redis选择2.0.5版本:https://repo.spring.io/libs-release/org/springframework/session/spring-session-data-redis/

Ps:这里用的spring都是比较高版本的,最好用本文的相应版本,否则会出现一些版本不合的奇葩错误。

具体步骤

创建项目

(1)在eclipse中创建一个web项目,命名为SpringSession。

(2)将上面下载的jar包全放到项目中WEB-INF/lib目录下。

spring mvc的配置

(1)在源码的src目录下创建config放置配置文件的包,以及创建com.sky.springsession放置java源码的包。

(2)在config包下创建applicationContext.xml文件,放置如下代码

<?xmlversion="1.0"encoding="UTF-8"?><beansxmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:p="http://www.springframework.org/schema/p"xmlns:aop="http://www.springframework.org/schema/aop"xmlns:tx="http://www.springframework.org/schema/tx"xmlns:context="http://www.springframework.org/schema/context"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsd"><context:component-scanbase-package="com.sky.springsession"/><context:annotation-config/></beans>

spring session的配置

在config包下创建spring-session.xml文件,放置如下代码

<?xmlversion="1.0"encoding="UTF-8"?><beansxmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:p="http://www.springframework.org/schema/p"xmlns:tx="http://www.springframework.org/schema/tx"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"><beanid="jedisPoolConfig"class="redis.clients.jedis.JedisPoolConfig"><propertyname="maxIdle"value="10"/><!--最大空闲连接数, 默认8个--><propertyname="maxTotal"value="20"/><!--最大连接数, 默认8个--><propertyname="blockWhenExhausted"value="true"/><!--连接耗尽时是否阻塞, false报异常,ture阻塞直到超时, 默认true--><propertyname="maxWaitMillis"value="1000"/><!--获取连接时的最大等待毫秒数(如果设置为阻塞时BlockWhenExhausted),如果超时就抛异常, 小于零:阻塞不确定的时间,  默认-1--><propertyname="testOnBorrow"value="true"/><!--在获取连接的时候检查有效性, 默认false--></bean><!--redis连接配置,依次为主机ip,端口,密码,是否使用池,连接池配置引用--><beanid="connectionFactory"class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory"p:host-name="192.168.17.132"p:port="6379"p:password="123456"p:usePool="true"p:pool-config-ref="jedisPoolConfig"></bean><!--配置spring-session--><beanclass="org.springframework.session.data.redis.config.annotation.web.http.RedisHttpSessionConfiguration"><!--session过期时间,单位是秒--><propertyname="maxInactiveIntervalInSeconds"value="30"></property></bean></beans>

Ps:注意,用了spring session后,在web.xml设置的session过期时间是无效。因为此session已经不是原来的存储在容器缓存内的session了,而是被封装多了一层后存储在redis的session。

web.xml的配置

<context-param><param-name>contextConfigLocation</param-name><param-value>classpath:config/*.xml</param-value></context-param><listener><listener-class>org.springframework.web.context.ContextLoaderListener</listener-class></listener><!-- spring session的过滤器配置,注意此过滤器必须放在其他过滤器之前 --><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></filter-mapping><!-- springmvc配置 --><servlet><servlet-name>springmvc</servlet-name><servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class><!-- 通过初始化参数,指定xml文件的位置 --><init-param><param-name>contextConfigLocation</param-name><param-value>classpath:config/applicationContext.xml</param-value></init-param><load-on-startup>1</load-on-startup></servlet><servlet-mapping><servlet-name>springmvc</servlet-name><url-pattern>/</url-pattern></servlet-mapping>

Ps:配置至此,就能够实现spring session通过存储到redis的session共享了。

创建jsp测试文件

(1)在WebContent目录下创建index.jsp,放置如下代码

<%@pagelanguage="java"contentType="text/html; charset=UTF-8"pageEncoding="UTF-8"%><%@pageimport="java.util.Date"%><!DOCTYPEhtml><html><head><metacharset="UTF-8"><title>springsession</title></head><body><%System.out.println(newDate()+"=============tomcat1=================");
session.setAttribute("tomcat1", "I am tomcat1");
%><h1>helloworld!</h1><br><p><%=session.getId()%>======<%=newDate()%></p><p>tomcat1======<%=session.getAttribute("tomcat1")%></p><p>tomcat2======<%=session.getAttribute("tomcat2")%></p></body></html>

(2)在WebContent目录下创建result.jsp,放置如下代码

<%@pagelanguage="java"contentType="text/html; charset=UTF-8"pageEncoding="UTF-8"%><%@pageimport="java.util.Date"%><!DOCTYPEhtml><html><head><metacharset="UTF-8"><title>springsession</title></head><body><h1>resulttomcat1</h1><br><p><%=session.getId()%>======<%=newDate()%></p><p>tomcat1======<%=session.getAttribute("tomcat1")%></p><p>tomcat2======<%=session.getAttribute("tomcat2")%></p></body></html>

开始测试

(1)打开浏览器,输入url:http://localhost:8080/SpringSession/

image.png(2)打开第二个标签页

image.png

(3)待30秒过后,刷新第二个标签页,发现tomcat1已经为null,说明上面的spring session的过期时间设置是有效的image.png

(4)当然想要看下spring session是否真的存在了redis,也可以到redis客户端上查看

image.png

目录
相关文章
|
NoSQL 安全 Java
深入理解 RedisConnectionFactory:Spring Data Redis 的核心组件
在 Spring Data Redis 中,`RedisConnectionFactory` 是核心组件,负责创建和管理与 Redis 的连接。它支持单机、集群及哨兵等多种模式,为上层组件(如 `RedisTemplate`)提供连接抽象。Spring 提供了 Lettuce 和 Jedis 两种主要实现,其中 Lettuce 因其线程安全和高性能特性被广泛推荐。通过手动配置或 Spring Boot 自动化配置,开发者可轻松集成 Redis,提升应用性能与扩展性。本文深入解析其作用、实现方式及常见问题解决方法,助你高效使用 Redis。
1584 4
|
存储 NoSQL 前端开发
Redis专题-实战篇一-基于Session和Redis实现登录业务
本项目基于SpringBoot实现黑马点评系统,涵盖Session与Redis两种登录方案。通过验证码登录、用户信息存储、拦截器校验等流程,解决集群环境下Session不共享问题,采用Redis替代Session实现数据共享与自动续期,提升系统可扩展性与安全性。
672 3
Redis专题-实战篇一-基于Session和Redis实现登录业务
|
NoSQL Java 调度
分布式锁与分布式锁使用 Redis 和 Spring Boot 进行调度锁(不带 ShedLock)
分布式锁是分布式系统中用于同步多节点访问共享资源的机制,防止并发操作带来的冲突。本文介绍了基于Spring Boot和Redis实现分布式锁的技术方案,涵盖锁的获取与释放、Redis配置、服务调度及多实例运行等内容,通过Docker Compose搭建环境,验证了锁的有效性与互斥特性。
1005 0
分布式锁与分布式锁使用 Redis 和 Spring Boot 进行调度锁(不带 ShedLock)
|
消息中间件 缓存 NoSQL
基于Spring Data Redis与RabbitMQ实现字符串缓存和计数功能(数据同步)
总的来说,借助Spring Data Redis和RabbitMQ,我们可以轻松实现字符串缓存和计数的功能。而关键的部分不过是一些"厨房的套路",一旦你掌握了这些套路,那么你就像厨师一样可以准备出一道道饕餮美食了。通过这种方式促进数据处理效率无疑将大大提高我们的生产力。
454 32
|
NoSQL Java Redis
Redis基本数据类型及Spring Data Redis应用
Redis 是开源高性能键值对数据库,支持 String、Hash、List、Set、Sorted Set 等数据结构,适用于缓存、消息队列、排行榜等场景。具备高性能、原子操作及丰富功能,是分布式系统核心组件。
938 2
|
Java Spring 容器
spring-session源码解读-4
spring session的生命周期 Session获取 spring-session实现了HttpServletRequest的子类–SessionRepositoryRequestWrapper,由它覆盖getSession方法,将由web容器处理的逻辑接管过来。 public HttpSession getSession(boolean create
2576 0
|
Java Spring 容器
spring-session源码解读-5
session通用策略 Session在浏览器通常是通过cookie保存的,cookie里保存了jessionid,代表用户的session id。一个访问路径只有一个session cookie(事实上在客户端就只有一个cookie,jsessionid是作为cookie值的一部分,这里把cookie抽象成类似服务器端的实现),也就是一个访问路径在一个浏览器上只有一个se
2557 0
|
Java Spring 容器
spring-session源码解读-3
ServletRequestWrapper Servlet规范从2.3起引入了ServletRequestWrapper包装类,它把调用交给被包装的ServletRequest来执行。这样就可以对ServletRequest进行扩展。例如Tomcat就是将自己的Request类作为包装类的实体。 public class ServletRequestWrapper i
3378 0
|
Java Spring 容器
spring-session源码解读-1
ServletContainerInitializer ServletContainerInitializer 也是 Servlet 3.0 新增的一个接口,主要用于在容器启动阶段通过编程风格注册Filter, Servlet以及Listener,以取代通过web.xml配置注册。这样就利于开发内聚的web应用框架。 例如Spring,我们使用它的web功能时,需要在we
2341 0
|
Java 容器 Spring
spring-session源码解读-2
启用redis session spring通过EnableRedisHttpSession注解来启用redid session @Import(RedisHttpSessionConfiguration.class) @Configuration public @interface EnableRedisHttpSession { int maxInacti
2823 0