1. session管理

spring session管理可以适用于很多功能,如:

登陆/退出

在线统计

限制账号多处登陆等

2. 监听器

相关的监听器主要有两个:HttpSessionListener和HttpSessionBindingListener

1. HttpSessionBindingListener

1. 使用

  • 实现HttpSessionBindingListener接口,其中两个方法,分别是绑定和解绑
  • 在controller中绑定属性:request.getSession().setAttribute("sessionBindListerner", new SessionBindingListener());

2. 触发条件

  • 触发绑定
  • 执行request.getSession().setAttribute("sessionBindListerner", new SessionBindingListener());
  • 触发解绑
  • 执行session.invalidate()
  • session超时,自动销毁时
  • 执行session.setAttribute("sessionBindListerner")
  • tomcat关闭时

2. HttpSessionListener

1. 使用

  • 实现HttpSessionListener接口
  • springboot中将类注册成bean即可
  • spring中在web.xml注册
<listener>
  <listener-class>com.test.OnlineUserListener</listener-class>
</listener>

2. 触发条件

  • 绑定触发
  • 新建session
  • 解绑触发
  • session.invalidate()
  • session超时

3. 关于session.invalidate()和session.removeAttribute("")

  • invalidate方法会清除session中的所有内容,同时删除session,调用之后再去调用session的其他方法会空指针。所以不推荐使用
  • removeAttrite会将某个属性置为失效

由于不推荐使用invalidate方法,那么退出的操作只能通过removeAttrite方式实现。如果需要统计session,则只能使用HttpSessionBindingListener,可以将登陆信息传入HttpSessionBindingListener的实现类中,然后在绑定解除的方法中,对session进行处理。

 

4. session持久化

1. 持久化的作用

  • 提高服务器内存的利用率,保证那些暂停活动的客户端在会话超时之前继续原来的会话
  • 在多台web服务器协同对外提供服务的集群系统中,使用Session的持久化技术,某台服务器可以将其中发生改变的Session对象复制给其他服务器。保证了在某台服务器停止工作后可以由其他服务器来接替它与客户端的会话
  • 在一个web应用程序重启时,服务器也会持久化该应用程序中所有HttpSession对象,保证客户端的会话活动仍可以继续。

2. 持久化的使用

tomcat默认会开启session的持久化,当服务器ctrl+c或者使用shutdown关闭时,会自动将session序列化并存储。当再启动服务器时再读取出来。

Tomcat使用Session Manager 类来管理Session的持久化,他提供了两个SessionManager类

  • org.apache.catalina.session.StandardManager
  • org.apache.catalina.session.PersistentManager

StandardManager是tomcat默认使用的,在web应用程序关闭时,对内存中的所有HttpSession对象进行持久化,把他们保存到文件系统中。默认的存储文件为 <tomcat 安装目录>/work/Catalina/<主机名>/<应用程序名>/sessions.ser PersistentManager比StandardManager更为灵活,只要某个设备提供了实现org.apache.catalina.Store接口的驱动类,PersistentManager就可以将HttpSession对象保存到该设备

具体参考:session持久化

3. 关闭持久化

tomcat的/context.xml配置文件,<Manager pathname="" /> 默认是注释掉的,去掉注释就会关闭自动持久化

5. spring-redis-session共享

在这个微服务,分布式的时代,很多传统的实现方案变的不再那么适用,比如传统的web服务将session放在内存中的情况,当web服务做水平扩展部署的时候,session共享就成了需要处理的问题。

  • 引入依赖包
<dependency>
    <groupId>org.springframework.session</groupId>
    <artifactId>spring-session</artifactId>
</dependency>

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
  • 配置redis
spring.redis.port=6379
spring.redis.host=127.0.0.1
spring.redis.password=******
spring.redis.pool.max-active=100
spring.redis.pool.max-idle=5
spring.redis.pool.max-wait=60000
  • 开启session的redis存储,以下方式均可
  • spring.session.store-type=redis
  • 启动类上加注解@EnableRedisHttpSession
  • 修改session存放在redis中的命名空间
@EnableRedisHttpSession(redisNamespace="xxxx")
spring.session.redis.namespace=xxxx
  • 修改session的超时时间
@EnableRedisHttpSession(maxInactiveIntervalInSeconds = 3600)

 springboot session的超时时间

# 小于1分钟会按照1分钟来计算,单位是分钟
server.session.timeout = 30

#常用的有
server.session.cookie.comment = #注释会话cookie。
server.session.cookie.domain = #会话cookie的域。
server.session.cookie.http-only =#“HttpOnly”标志为会话cookie。
server.session.cookie.max-age = #会话cookie的最大年龄(以秒为单位)。
server.session.cookie.name = #会话cookie名称。
server.session.cookie.path = #会话cookie的路径。
server.session.cookie.secure = #“Secure”标志为会话cookie。
server.session.persistent = false #在重新启动之间持续会话数据。
server.session.store-dir = #用于存储会话数据的目录。
server.session.timeout = #会话超时(秒)。
server.session.tracking-modes =#会话跟踪模式(以下一个或多个:“cookie”,“url”,“ssl”)

 或者使用java的方式

@Bean
public EmbeddedServletContainerCustomizer containerCustomizer(){
       return new EmbeddedServletContainerCustomizer() {
           @Override
           public void customize(ConfigurableEmbeddedServletContainer container) {
                container.setSessionTimeout(1800);//单位为S
          }
    };
}
  •  我们可以采用javaconfig方式自定义策略来设置超时以及设置cookies名称,如下我们设置超时时间是1800秒,cookies名为MYSESSIONID
@Bean
public CookieHttpSessionStrategy cookieHttpSessionStrategy(){
    CookieHttpSessionStrategy strategy=new CookieHttpSessionStrategy();
    DefaultCookieSerializer cookieSerializer=new DefaultCookieSerializer();
    cookieSerializer.setCookieName("MYSESSIONID");//cookies名称
    cookieSerializer.setCookieMaxAge(1800);//过期时间(秒)
    strategy.setCookieSerializer(cookieSerializer);
    return strategy;
}

6. session的自定义操作

如果想自定义session的操作,就需要用到HttpSessionBindingListener和HttpSessionListener这两个监听器。操作如下:

  • 统计新增

在创建session的时候触发,HttpSessionListener的sessionCreated方法

  • 登陆

获取sessionId和userId,将信息放在地方比如redis,如果需要,可以存储sessionId->userId以及userId->sessionId的索引关系,并且存储创建时间等其他信息

  • 写session

可以将信息写入redis,绑定到对应的sessionId下

  • 判断登陆

查询redis是否有对应的信息

  • session过期

HttpSessionListener的sessionDestroyed方法会被触发,可以在这里面做一些操作,比如清楚redis信息,记录过期时间等

  • 退出登陆

清除reids的信息

  • 统计在线人数

统计redis的数据就行了

  • 统计在线时长

记录redis数据的创建和销毁时间

涉及的到的问题

  • tomcat重启

如果tomcat有持久化,则重启之后session不会失效,请求访问时,接收都的还是之前的sessionId。

  • tomcat关闭,session失效

tomcat关闭,session失效,redis中的信息会一直都在,如果时间久了,会有很多垃圾数据。所以重启tomcat时,可以对redis数据清洗一遍,去掉已经失效的数据

  • 为什么不用HttpSessionBindingListener

这个监听器需要绑定到某个session之上,而且关闭tomcat时,会调用其解绑方法,如果解绑方法里面有清除reis的操作,那么关闭tomcat时reids会被全部清空,所以还是用HttpSessionListener吧