You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

多Servlet共享变量实现计数器:变量定义与未初始化读取问题

简易计数器Servlet共享变量问题

需求说明

创建一个简易计数器应用,包含三个不同的Servlet:

  • 读取数值:ReadValue,处理GET请求
  • 递增数值:Increment,处理POST请求
  • 递减数值:Decrement,处理POST请求

原代码示例

ReadValue.java

@WebServlet("/readValue")
public class ReadValue extends HttpServlet {
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
        throws ServletException, IOException
    {
        response.getWriter().println("Value is " + value);
    }
}

Increment.java

@WebServlet("/incrementValue")
public class Increment extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
        throws ServletException, IOException
    {
        value++;
        response.getWriter().println("Now value is " + value);
    }
}

Decrement.java

@WebServlet("/decrementValue")
public class Decrement extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
        throws ServletException, IOException
    {
        if (value > 0) {
            value--;
            response.getWriter().println("Now value is " + value);
        }
    }
}

问题

  1. 变量value应该定义在何处?
  2. 了解ServletContext可用于多个Servlet间共享变量,但如果ServletContext未被设置时就调用读取它的Servlet,会发生什么?

解答

1. 变量value的定义位置

变量value需要放在所有Servlet都能访问的共享存储容器中,最合适的就是ServletContext(你提到的ServerContext是笔误,正确名称是ServletContext)。

原因:每个Servlet是单例实例,但三个Servlet是不同的类实例,若把value定义为各自的成员变量,三个Servlet会维护独立的数值,完全达不到共享计数的效果。而ServletContext是Web应用的全局上下文,整个应用内所有Servlet都可以访问其中的属性,完美适配多Servlet共享变量的场景。

2. 未设置ServletContext变量时调用读取Servlet的后果

如果直接调用读取Servlet,而ServletContext中还没存入value,getAttribute("counterValue")会返回null。此时若直接使用这个null值(比如拼接字符串、做自增/自减运算),会触发NullPointerException空指针异常,导致请求报错。

优化后的代码实现

方式1:在每个Servlet中判断并初始化

ReadValue.java(读取)
@WebServlet("/readValue")
public class ReadValue extends HttpServlet {
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
        throws ServletException, IOException
    {
        ServletContext context = getServletContext();
        // 检查变量是否存在,不存在则初始化为0
        Integer value = (Integer) context.getAttribute("counterValue");
        if (value == null) {
            value = 0;
            context.setAttribute("counterValue", value);
        }
        response.getWriter().println("Value is " + value);
    }
}
Increment.java(递增)
@WebServlet("/incrementValue")
public class Increment extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
        throws ServletException, IOException
    {
        ServletContext context = getServletContext();
        Integer value = (Integer) context.getAttribute("counterValue");
        if (value == null) {
            value = 0;
        }
        value++;
        context.setAttribute("counterValue", value);
        response.getWriter().println("Now value is " + value);
    }
}
Decrement.java(递减)
@WebServlet("/decrementValue")
public class Decrement extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
        throws ServletException, IOException
    {
        ServletContext context = getServletContext();
        Integer value = (Integer) context.getAttribute("counterValue");
        if (value == null) {
            value = 0;
        }
        if (value > 0) {
            value--;
            context.setAttribute("counterValue", value);
        }
        response.getWriter().println("Now value is " + value);
    }
}

方式2:用监听器全局初始化(更优雅)

创建ServletContextListener,在Web应用启动时就初始化计数器值,避免每个Servlet都做判断:

@WebListener
public class CounterInitListener implements ServletContextListener {
    @Override
    public void contextInitialized(ServletContextEvent sce) {
        // 应用启动时初始化计数器为0
        ServletContext context = sce.getServletContext();
        context.setAttribute("counterValue", 0);
    }

    @Override
    public void contextDestroyed(ServletContextEvent sce) {
        // 应用销毁时可选择保存计数器值到持久化存储(可选)
    }
}

这种方式下,所有Servlet都可以直接从ServletContext获取counterValue,无需再做null判断。


内容的提问来源于stack exchange,提问作者bui3

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.12 00:05:11