| 語法 | 名稱 | 生成位置 | 作用域 | 線程安全 |
|---|---|---|---|---|
<% int count = 0; %> | Scriptlet (腳本片段) | _jspService() 方法內部 | 請求級 (每次請求重新初始化) | 安全 (局部變量) |
<%! int count = 0; %> | Declaration (聲明) | Servlet 類成員變量位置 | **實例級** (同一 JSP 對應的 Servlet 實例共享) | **不安全** (多線程共享實例變量) |
test1.jsp, test2.jsp)<%! int intCount = 0; %>
<%
intCount++;
out.print("第 " + intCount + " 人次進入本頁面!");
%>
JRun 3 + JDK 1.2 (經典環境,現代容器行為一致)
intCount=0 僅在類加載時執行一次(首次請求)。test1.jsp 與 test2.jsp 編譯為不同 Servlet 類,各自擁有獨立的 intCount 成員變量。JSP 編譯為 Servlet 類結構:
public class test1_jsp extends HttpJspBase {
// <%! ... %> 生成在此處
int intCount = 0;
public void _jspService(HttpServletRequest request, HttpServletResponse response) {
// <% ... %> 生成在此處
intCount++;
out.print("第 " + intCount + " 人次進入本頁面!");
}
}
intCount 屬於該實例,**所有請求線程共享**。行為類似 ASP 的 Application("count"):全局共享、進程生命週期內持久。但 JSP 聲明**不支持集群**,多 JVM 實例各自維護副本。
count++ 非原子操作,導致漏計/重計。<%! User currentUser; %>,多用戶將互相覆蓋,嚴重安全事故。| 需求 | 正確範圍 | 實現方式 |
|---|---|---|
| 請求級計數/數據 | page / request | <% int count = 0; %> 或 request.setAttribute() |
| 用戶會話級數據 | session | session.setAttribute("count", val) |
| 全局應用級計數/配置 | application | application.setAttribute("count", val) + 同步/原子類 |
| 全局單例服務/DAO | application | Spring Bean / ServletContextListener 初始化 / 靜態工具類 |