利用 JSP application 內置對象(對應 ServletContext)的生命周期特性:隨 Web 應用啟動而創建,隨應用關閉而銷毀,全局唯一、多用戶共享,實現簡單的全站訪問計數器。
counter.jsp<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>訪問計數器演示</title>
</head>
<body>
<%
// 1. 讀取初始化參數(需在 web.xml 中配置 <context-param>)
String initParam = application.getInitParameter("test2");
out.print("test2=" + initParam + "<br>");
// 2. 從 application 域獲取計數器
Object obj = application.getAttribute("count");
// 3. 首次訪問初始化
if (obj == null) {
application.setAttribute("count", 1);
obj = 1;
}
// 4. 計數器遞增
long count = Long.parseLong(obj.toString());
count++;
// 5. 輸出當前計數
out.print("count=" + count);
// 6. 更新回 application 域,供下次訪問使用
application.setAttribute("count", count);
%>
</body>
</html>
| 方法/屬性 | 說明 |
|---|---|
application.getInitParameter(name) | 讀取 web.xml 中 <context-param> 定義的全局初始化參數。 |
application.getAttribute(name) | 從 ServletContext 獲取屬性值,返回 Object,需轉型。 |
application.setAttribute(name, value) | 向 ServletContext 存放屬性,全局可見,線程不安全。 |
上述代碼在高併發下存在競態條件:多線程同時讀取舊值、遞增、寫回,導致計數丟失。生產環境建議:
AtomicLong(推薦)<%
// 初始化階段(可放在 ServletContextListener 中)
AtomicLong counter = (AtomicLong) application.getAttribute("counter");
if (counter == null) {
counter = new AtomicLong(0);
application.setAttribute("counter", counter);
}
long current = counter.incrementAndGet(); // 原子遞增
out.print("count=" + current);
%>
<%
synchronized (application) {
Object obj = application.getAttribute("count");
long count = (obj == null) ? 1 : Long.parseLong(obj.toString()) + 1;
application.setAttribute("count", count);
out.print("count=" + count);
}
%>
<context-param>
<param-name>test2</param-name>
<param-value>init-value-demo</param-value>
</context-param>
application 域適合存放全局共享、讀多寫少的數據(如配置、緩存、計數器)。AtomicLong 或 LongAdder(Java 8+)。