Tomcat如何禁用session
阅读原文时间:2021年04月20日阅读:1

有时候我们不需要用到session,而session在tomcat中是属于关键功能,它在启动的时候会自动创建,这样就会消耗一定的内存空间,如果访问量大了session就会产生很多。这样也不利于我们进行分布扩展。
 

JSESSIONID的产生机制

tomcat只有在程序中使用了 xxx.getSession() 的时候才会创建session(JSESSIONID是它的标识),其他任何时候都不会主动去创建。

这个时候有人问了,我的程序里明确没有调用 xxx.getSession(),为什么还会创建session?原因是用到了jsp作为渲染机制,你去看一下在tomcat的工作目录中所对应的jsp编译好的.class或者也有.java文件,能够看到:session = pageContext.getSession();这样一段代码。这个session也就是jsp几个内置对象中含有session对象的来源。所以,只要你用到了 jsp,那么就会默认产生session。 

那不用jsp,而用 servlet 的话,会不会主动创建 session 呢?不会的,因为对于Controller或者Action来说,本质上还是servlet。不会的,除非你自己写 xxx.getSession()。

那我也不用jsp,用其他的模板引擎,比如 freemarker 或者 Thymeleaf,会不会主动创建 session 呢?不会的,除非这个模板引擎中也主动调用xxx.getSession,否则不会。

那我既不用jsp,也不用servlet,用的是 spring的Controller或者 struts 的Action,那会不会主动创建 session 呢?不会的,因为对于Controller或者Action来说,本质上还是servlet。

解决办法

通过上面的机制分析,很明显禁用tomcat的session的最好途径就是告诉jsp,不要主动创建session,那么方式是在每个jsp页面中加入:

<%@ page session="false" %>

这种方式需要在每一个jsp页面加入以上代码,或者引用共同的jsp。如果某一个页面忘记引用或者是JAVA部分代码主动的去获取了xxx.getSession(),那么还是会产生session。

所以本人倾向于第二种方式,在tomcat中停止创建session,自定义一个SessionManager

package com.noSession;

import java.io.IOException;
import org.apache.catalina.Lifecycle;
import org.apache.catalina.LifecycleException;
import org.apache.catalina.LifecycleState;
import org.apache.catalina.Session;
import org.apache.catalina.session.ManagerBase;

public class SessionManager extends ManagerBase implements Lifecycle {

    @Override
    protected synchronized void startInternal() throws LifecycleException {

        super.startInternal();
        setState(LifecycleState.STARTING);
    }

    @Override
    protected synchronized void stopInternal() throws LifecycleException {

        setState(LifecycleState.STOPPING);
    }

    @Override
    public void load() throws ClassNotFoundException, IOException {
    }

    @Override
    public void unload() throws IOException {
    }

    @Override
    public Session createSession(String sessionId) {

        return null;
    }

    @Override
    public Session createEmptySession() {

        return null;
    }

}

注意,上面这个SessionManager中createSession、createEmptySession方法返回的是null。

在使用jsp的时候会报错Page needs a session and none is available。

有一下两种解决方案:

1.在jsp中加上

<%@ page session="false" %>

2.全局使用同一个session

import java.io.IOException;

import org.apache.catalina.Lifecycle;
import org.apache.catalina.LifecycleException;
import org.apache.catalina.LifecycleState;
import org.apache.catalina.Session;
import org.apache.catalina.session.ManagerBase;

public class SessionManager extends ManagerBase implements Lifecycle {

    private Session globalSession;

    @Override
    protected synchronized void startInternal() throws LifecycleException {
        super.startInternal();
        setState(LifecycleState.STARTING);
    }

    @Override
    protected synchronized void stopInternal() throws LifecycleException {
        setState(LifecycleState.STOPPING);
    }

    @Override
    public void load() throws ClassNotFoundException, IOException {
    }

    @Override
    public void unload() throws IOException {
    }

    @Override
    public Session createSession(String sessionId) {
        if(globalSession == null) {
            globalSession = super.createSession(sessionId);
        } else {
            globalSession.setValid(true);
        }

        return globalSession;
    }

    @Override
    public Session createEmptySession() {
        if(globalSession == null) {
            globalSession = super.createSession(sessionId);
        } else {
            globalSession.setValid(true);
        }

        return globalSession;
    }

}

还需要注意这个globalSession需要进行激活,否则在tomcat的session失效后,会将此session标注为失效,那么尽管globalSession还是存在的,但是是失效的状态,还是会报错说session不存在。所以globalSession.setValid(true);这句很重要。

然后,在tomcat的server.xml中进行设置,或者配置host的其他方式

<Context docBase="D:\test" path="/test" reloadable="false" sessionCookieName="yoursessionname">
    <Manager className="xxx.xxx.SessionManager" />
</Context>

上面的sessionCookieName默认是JSESSIONID,其实这个是有点点缺陷的,能够让别人知道你的应用是用java开发的,所以,换个其他的名字会更好一些。

最后,将SessionManager打包为jar包,放到tomcat的lib文件夹下面