J2EE 應用性能瓶頸多集中在 Web 層。本文梳理 7 個經過生產驗證的優化技巧,涵蓋初始化緩存、會話控制、壓縮傳輸、線程模型、包含機制、Bean 作用域、代碼微優化,助你構建高吞吐、低延遲的 Web 應用。
Servlet.init() 中緩存靜態資源init() 僅在 Servlet 實例化後調用一次,適合載入昂貴資源:
public class ControllerServlet extends HttpServlet {
private DataSource dataSource; // 線程安全,單例
@Override
public void init(ServletConfig config) throws ServletException {
super.init(config);
try {
Context ctx = new InitialContext();
dataSource = (DataSource) ctx.lookup("java:comp/env/jdbc/MyDS");
} catch (NamingException e) {
throw new ServletException("DataSource lookup failed", e);
}
}
protected DataSource getDataSource() { return dataSource; }
}
效果:避免每請求 JNDI 查找,降低延遲 ~1-5ms。
Context reloadable="false" (默認)。| 策略 | 做法 | 收益 |
|---|---|---|
| 禁用無用 Session | JSP 頁面指令 <%@ page session="false" %> | 減少 Session 創建/序列化開銷 |
| 不存大對象 | 僅存 ID/Token,大數據放 Redis/DB | 降低序列化體積與 GC 壓力 |
| 及時失效 | 登出調用 session.invalidate() | 釋放內存,防囤積 |
| 縮短超時 | web.xml <session-timeout>15</session-timeout> (分鐘) | 減少併發 Session 數 |
public void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {
String acceptEncoding = req.getHeader("Accept-Encoding");
OutputStream out;
if (acceptEncoding != null && acceptEncoding.contains("gzip")) {
resp.setHeader("Content-Encoding", "gzip");
out = new GZIPOutputStream(resp.getOutputStream());
} else {
out = resp.getOutputStream();
}
// 後續寫入 out...
}
SingleThreadModel,擁抱線程池SingleThreadModel 導致容器為每請求創建 Servlet 實例,**極度浪費內存/CPU**,Servlet 2.4 已棄用。server.xml):<Executor name="tomcatThreadPool" namePrefix="catalina-exec-"
maxThreads="200" minSpareThreads="25" maxIdleTime="60000" />
<Connector executor="tomcatThreadPool" port="8080" ... />
效果:線程復用,併發尖峰平滑處理,無創建風暴。
| 機制 | 語法 | 階段 | 性能 | 適用場景 |
|---|---|---|---|---|
| 靜態包含 | <%@ include file="fragment.jsp" %> | 編譯期合併為單一 Servlet | **最快** (無額外請求/包裝) | 通用片段:頭部、底部、側欄、工具函數 |
| 動態包含 | <jsp:include page="dynamic.jsp" flush="true"/> | 請求期轉發包含 | 較慢 (額外 request/response 包裝) | 高度動態、需獨立編譯、條件包含 |
原則:能靜態包含就靜態包含。
<jsp:useBean> 作用域<jsp:useBean id="user" class="com.example.User" scope="request"/>
| scope | 生命週期 | 適用場景 |
|---|---|---|
| page | 當前頁面渲染期間 (默認) | 臨時工具對象、格式化輔助 |
| request | 一次 HTTP 請求 | 表單數據封裝、請求級緩存 |
| session | 用戶會話期間 | 登入用戶信息、購物車 |
| application | 整個 Web 應用生命週期 | 全局配置、靜態字典、共享緩存 |
誤區:請求級數據用 session 導致內存洩漏、垃圾對象堆積、GC 頻繁。
StringBuilder 替代 + (循環/高頻)。Log4j2/SLF4J 異步輸出,禁用 System.out.println (同步阻塞 IO)。ServletOutputStream,文本用 PrintWriter (避免雙向轉換)。PreparedStatement + 批處理 + 連接池。new ArrayList<>(expectedSize)。性能優化無銀彈,但上述 7 技巧覆蓋了 Web 層 80%+ 的常見瓶頸。原則:**緩存靜態、壓縮傳輸、縮小作用域、復用線程、靜態包含、異步日誌**。配合 APM (Pinpoint/SkyWalking) 持續觀測,方能行穩致遠。