第一章 Session会话管理
1.1 Session机制
由于http协议是无状态的协议,每一次对话完成,会话就结束了。服务器不能记住这个人,下次再对话时,服务器会把对话的人当作一个完全的陌生人来对待。
所以需要某种机制来识别具体的用户,这个机制就是session。
1.2 cookie
服务器端需要使用cookie来识别客户。每次http请求时,客户端都会发送相应的cookie信息到服务端。
第一次创建Session时,服务器端会在http协议中向客户端的cookie中记录一个sessionID,以后每次请求把这个会话ID发送到服务器端,这样服务器端就知道客户端是谁了。
1.3 url重写
如果客户端浏览器禁用了cookie,就会使用url重写的技术来进行session会话跟踪,即每次http交互,url后面都会被附加上一个注入sessionId=xxxxxxxx这样的参数,服务端据此来识别客户端是谁。
1.4 session存放机制
Session容器对象中key是sessionid,value是session对象。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-33beiDLn-1666596165518)(C:\Users\ADMINI~1\AppData\Local\Temp\WeChat Files\e3819f39968460098f9e8f2f25aed90.jpg)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-F4EXjAMI-1666596165519)(C:\Users\ADMINI~1\AppData\Local\Temp\WeChat Files\a79ce0ebe08c8e5feb12963cc407eba.jpg)]
1.5 集群丢失session原因
session容器不共享
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-T2jPyc9f-1666596165519)(C:\Users\ADMINI~1\AppData\Local\Temp\WeChat Files\5b835ec0f9d31ada68c8addcfc790b8.jpg)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Wd24xE0M-1666596165520)(C:\Users\ADMINI~1\AppData\Local\Temp\WeChat Files\aee564468cfc63ee54a7c11dfcd00df.jpg)]
1.6 session会话共享方案
第一种:使用容器扩展插件来实现,比如基于tomcat的tomcat-redis-session-manager插件,基于jetty的jetty-session-redis插件,memcached-session-manager插件。
其底层是,复制session到其他服务器,所以会有一定延迟,也不能部署太多服务器。
第二种:使用Nginx负载均衡的ip_hash策略实现用户每次访问都绑定到同一台具体的后台tomcat服务器实现session。但ip不能变,如果手机换了基站,ip就会变,导致session丢失。
第三种:自己写一套session会话管理的工具类,在需要使用会话的时候都从自己的工具类中获取,而工具类后端存储可以放到redis中。
第四种:使用框架的会话管理工具,也就是springsession。
第二章 Springsession简介
springsession把servlet容器实现的httpsession替换为springsession专注于解决session管理问题,session信息存储在redis中,可简单快速且无缝的集成到应用中。
springsession的特性:
- 提供用户session管理的API和实现
- 提供httpsession,一种里的方式取代为把容器的session,比如tomcat中的session
- 支持集群的session处理,不必绑定到具体的web容器去解决集群下的session共享问题。
2.1 同域名下,同项目下的session共享
<!--要使用springsession,需要引入依赖包-->
<dependency>
<groupId>org.springframework.session</groupId>
<artifactId>spring-session-data-redis</artifactId> <!--这里需要redis用来存储sessionId-->
<version>1.3.1.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>5.2.5.RELEASE</version>
</dependency>
<!--依赖加完后,就需要配置applicationContext.xml和springsession.xml-->
applicationContext.xml
<import resource="springsession.xml">
springsession.xml
<!--
启动spring的注解支持,因为springsession中使用到了spring的相关注解,因此需要启动spring的注解这一步可以省略
通常工作时我们会使用<context:component-scan base-package="com"/>来进行包扫描,这个标签中的功能就包含了
<context:annotation-config/>的功能,因此实际工作时,这个步骤可以省略。
-->
<context:annotation-config/>
<!--配置一个用于专门配置springsession的bean标签配置-->
<bean id="redisHttpSessionConfiguration" class="org.springframework.session.data.redis.config.annotation.web.http.RedisHttpSessionConfiguration">
</bean>
<!--配置redis,这是可选的配置步骤,如果当前工程已经配置过redis那么这个配置可以省略-->
<bean id="jedisConnectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory">
<property name="hostName" value="192.168.213.133"/>
<property name="port" value="6379"/>
</bean>
<!--最后配置web.xml-->
<!--添加filter,固定的,不能自定义name,引入了springsession-->
<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来开发web工程,而web工程不需要启动监听器-->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
2.2 同域名下,不同项目下的session共享
<!--只需要修改springsession.xml文件即可-->
<!--配置一个用于专门配置springsession的bean标签配置-->
<bean id="redisHttpSessionConfiguration" class="org.springframework.session.data.redis.config.annotation.web.http.RedisHttpSessionConfiguration">
<!--注入一个cookie序列化规则对象-->
<property name="cookieSerializer" ref="defaultCookieSerializer"/>
</bean>
<!--配置一个cookie序列化规则对象,用于该百年cookie的存放规则-->
<bean id="defaultCookieSerializer" class="org.springframework.session.web.http.DefaultCookieSerializer">
<!--指定springsession的sessionid存放在域名根路径下,用于实现同域名下不同项目之间的session共享-->
<property name="cookiePath" value="/"/>
</bean>
2.3 同根域名,不同二级子域名下的session共享
<!--只需要修改springsession.xml文件即可-->
<!--配置一个用于专门配置springsession的bean标签配置-->
<bean id="redisHttpSessionConfiguration" class="org.springframework.session.data.redis.config.annotation.web.http.RedisHttpSessionConfiguration">
<!--注入一个cookie序列化规则对象-->
<property name="cookieSerializer" ref="defaultCookieSerializer"/>
</bean>
<!--配置一个cookie序列化规则对象,用于该百年cookie的存放规则-->
<bean id="defaultCookieSerializer" class="org.springframework.session.web.http.DefaultCookieSerializer">
<!--指定springsession的sessionid存放在域名根路径下,用于实现同域名下不同项目之间的session共享-->
<property name="cookiePath" value="/"/>
<property name="domainName" value="myweb.com"/>
</bean>
2.4 单点登陆(完全不同域名session共享)
例如www.taobao.com和www.tmall.com,域名完全不同,但是登录信息确一致
对于不同根域名的场景,要实现一处登录,处处登录,springsession不支持这样的功能。
单点登录(single sign on ,sso)
第三章 springboot整合springsession
<!--加入依赖-->
<!--springboot集成redis起步依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!--springsession 将数据存入redis依赖-->
<dependency>
<groupId>org.springframework.session</groupId>
<artifactId>spring-session-data-redis</artifactId>
<version>1.3.1.RELEASE</version>
</dependency>
#配置文件
#连接redis
spring.redis.port=6379
spring.redis.host=192.168.213.133
#设置session生命周期
server.reactive.session.timeout=30m
#指定Cookie的存放路径为根路径,用于实现同域名不同项目的session共享
server.servlet.session.cookie.path=/
#指定cookie的存放路径为根域名,用于实现同根域名,不同二级子域名的session共享
server.servlet.session.cookie.domain=myweb.com
#如果上面两个都没有,则就是同域名同项目下的session共享
放路径为根路径,用于实现同域名不同项目的session共享
server.servlet.session.cookie.path=/
#指定cookie的存放路径为根域名,用于实现同根域名,不同二级子域名的session共享
server.servlet.session.cookie.domain=myweb.com
#如果上面两个都没有,则就是同域名同项目下的session共享