Session会话管理

HTTP协议是无状态的,但Cookie赋予了浏览器在客户端保存会话状态的能力。此外,基于Cookie也可以间接实现在服务端保存会话状态的能力,我们通常将其称为Session。Servlet规范中,Session对象专门用于保存服务端会话状态。这篇笔记我们学习Servlet规范中Session的用法。

Servlet中Session的实现原理

Servlet规范中,Session是基于Servlet容器内存和Cookie中的JSESSIONID属性实现的。浏览器第一次访问服务端程序时,浏览器请求不会带上任何Cookie,此时服务端的响应会包含Set-Cookie响应头来设置JSESSIONID。浏览器后续访问时就会带上这个Cookie,在服务端,一些信息会被缓存到Servlet容器的JVM内存中,基于JSESSIONID我们就可以判断该数据属于哪个会话。

至于集群模式如何实现Session,通常有两种方式:Session复制和统一存储。前者通常需要Servlet中间件支持Session复制,例如将Wildfly配置为Cluster模式;后者则是将Session信息统一存储到Redis等缓存数据库中,这样就避免了基于内存的Session在集群模式下出现不一致的情况。

Session读写

Servlet规范对于Session进行了封装,使用非常简单,我们通常不需要考虑设置Cookie等操作,它们都由Servlet容器维护,下面例子中我们实现了Session信息的读写。

package com.gacfox.demo.demoweb;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class DemoServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // 读取Session
        String sessionData = (String) request.getSession().getAttribute("text");
        System.out.println(sessionData);
        // 写入Session
        request.getSession().setAttribute("text", "hello");
    }
}

例子代码中,我们在Session中写入和读取了一个字符串对象。

Session主动失效

调用invalidate()方法可以主动清空Session。

request.getSession().invalidate();

虽然我们能主动清空当前会话的Session,但Servlet规范并没有提供一个主动清空任意会话Session的能力,这本质是因为Servlet规范没有提供一个基于SessionID查找任意会话Session的接口,因此诸如“管理员踢人下线”这种功能实现起来就比较曲折和绕弯,我们不得不缓存一些额外信息来辅助Session的失效判断,这大概也是Servlet规范的一个小缺陷。

监听Session的创建和销毁

HttpSessionListener能够在Session创建和销毁时监听到对应的消息,下面是一个例子。

package com.gacfox.demo.demoweb.listerner;

import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;

public class DemoSessionListener implements HttpSessionListener {
    @Override
    public void sessionCreated(HttpSessionEvent httpSessionEvent) {
        String sessionId = httpSessionEvent.getSession().getId();
        System.out.println(sessionId);
    }
}

代码中我们监听了Session创建的消息,并打印了SessionID。

作者:Gacfox
版权声明:本网站为非盈利性质,文章如非特殊说明均为原创,版权遵循知识共享协议CC BY-NC-ND 4.0进行授权,转载必须署名,禁止用于商业目的或演绎修改后转载。
Copyright © 2017-2024 Gacfox All Rights Reserved.
Build with NextJS | Sitemap