public class StrutsPrepareAndExecuteFilter extends StrutsFilterBase {
// 1. 準備階段操作封裝 (ActionMapping, Interceptor 等)
protected PrepareOperations prepare;
// 2. 執行階段操作封裝 (ActionInvocation, Result 執行)
protected ExecuteOperations execute;
// 3. 排除模式列表 (不經過 Struts 處理的靜態資源路徑)
protected List excludedPatterns = null;
// 4. 內部配置物件 (非公開字段)
// protected ConfigurationManager configurationManager;
}
關鍵認知:Filter 實例是單例,但核心操作物件是請求範圍內創建的。
prepare 和 execute 是無狀態的工具類實例,內部不持有請求相關資料。ActionContext、ActionInvocation、ValueStack 等請求級物件,這些物件儲存於 `ThreadLocal` (如 `ActionContext.getContext()`) 中,天然線程隔離。excludedPatterns 僅在初始化時讀取配置,運行期只讀,無並發寫入風險。
HTTP Request
↓
StrutsPrepareAndExecuteFilter.doFilter()
↓
prepare.prepare(wrapper, chain) // 建立 ActionContext, ActionMapping, 執行 PrepareInterceptor
↓
execute.execute(wrapper) // 建立 ActionInvocation, 執行 Action + Interceptors + Result
↓
HTTP Response
「Filter 有字段 `prepare`/`execute` 會導致線程安全問題」—— 錯誤。這兩個字段指向的是無狀態的單例策略物件,真正的請求狀態在 `ThreadLocal` 中。
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
try {
prepare.setEncodingAndLocale(request, response);
prepare.createActionContext(request, response); // 關鍵:創建請求級 ActionContext (ThreadLocal)
prepare.assignParams(request, response); // 參數注入
if (excludedPatterns != null && prepare.isUrlExcluded(request, excludedPatterns)) {
chain.doFilter(request, response);
return;
}
ActionMapping mapping = prepare.findActionMapping(request, response);
if (mapping == null) {
chain.doFilter(request, response);
} else {
execute.executeAction(mapping, request, response); // 執行 Action 鏈
}
} finally {
prepare.cleanupRequest(request); // 清理 ThreadLocal,防止記憶體洩漏
}
}
prepare、execute、excludedPatterns。PrepareOperations / ExecuteOperations 策略模式設計,有助於擴展自定義攔截邏輯。