首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Struts 1 請求處理流程源碼深度解析:從 ActionServlet 到 RequestProcessor 的完整鏈路

     編輯:Java 相關知識

宏觀流程圖

ActionServlet 與 RequestProcessor 處理流程

核心兩類:ActionServlet(前端控制器)與 RequestProcessor(請求處理模板)。

ActionServlet:入口與分發

process(HttpServletRequest, HttpServletResponse)

protected void process(HttpServletRequest request, HttpServletResponse response)
    throws IOException, ServletException {
  ModuleUtils.getInstance().selectModule(request, getServletContext());
  ModuleConfig config = getModuleConfig(request);
  RequestProcessor processor = getProcessorForModule(config);
  if (processor == null) {
    processor = getRequestProcessor(config);
  }
  processor.process(request, response);  // 委託給 RequestProcessor
}
  • 選擇模塊(多模塊支持)。
  • 獲取/創建對應模塊的 RequestProcessor 實例。
  • 核心邏輯完全委託,符合單一職責。

RequestProcessor:模板方法定義完整生命週期

process(HttpServletRequest, HttpServletResponse) 主流程

public void process(HttpServletRequest request, HttpServletResponse response)
    throws IOException, ServletException {
  // 1. 多部分請求包裝
  request = processMultipart(request);
  
  // 2. 路徑識別與映射
  String path = processPath(request, response);
  if (path == null) return;
  
  // 3. Locale、Content-Type、No-Cache 設置
  processLocale(request, response);
  processContent(request, response);
  processNoCache(request, response);
  
  // 4. 預處理鉤子
  if (!processPreprocess(request, response)) return;
  
  // 5. 清理舊消息
  processCachedMessages(request, response);
  
  // 6. ActionMapping 查找
  ActionMapping mapping = processMapping(request, response, path);
  if (mapping == null) return;
  
  // 7. 角色權限檢查
  if (!processRoles(request, response, mapping)) return;
  
  // 8. ActionForm 創建、填充、驗證
  ActionForm form = processActionForm(request, response, mapping);
  processPopulate(request, response, form, mapping);
  try {
    if (!processValidate(request, response, form, mapping)) return;
  } catch (InvalidCancelException e) {
    ActionForward forward = processException(request, response, e, form, mapping);
    processForwardConfig(request, response, forward);
    return;
  }
  
  // 9. Forward/Include 配置檢查
  if (!processForward(request, response, mapping)) return;
  if (!processInclude(request, response, mapping)) return;
  
  // 10. Action 創建與執行
  Action action = processActionCreate(request, response, mapping);
  if (action == null) return;
  ActionForward forward = processActionPerform(request, response, action, form, mapping);
  
  // 11. 結果轉發
  processForwardConfig(request, response, forward);
}

關鍵子流程詳解

1. processMultipart:文件上傳檢測

protected HttpServletRequest processMultipart(HttpServletRequest request) {
  if (!"POST".equalsIgnoreCase(request.getMethod())) return request;
  String contentType = request.getContentType();
  if (contentType != null && contentType.startsWith("multipart/form-data")) {
    return new MultipartRequestWrapper(request);  // 包裝解析文件流
  }
  return request;
}

2. processPath:路徑提取與標準化

  • 前綴匹配:獲取 pathInfo。
  • 擴展名匹配:獲取 servletPath,去除模塊前綴(/module)和擴展名(.do)。
  • 例:https://localhost:8080/struts_login/login.do → /login。

3. processMapping:ActionMapping 解析

  • 根據 path 查找 ActionConfig。

  • 找到則存入請求屬性 Globals.MAPPING_KEY。

  • 未找到則查找 unknown="true" 的備用映射。

  • 仍無則發送 400 錯誤。

4. processActionForm 與 processPopulate:表單生命週期

  • 創建:RequestUtils.createActionForm() 實例化。

  • 作用域存儲:request 或 session(按 mapping.getScope())。

  • 填充:processPopulate() 調用 BeanUtils.populate() 綁定請求參數,先調用 reset() 重置默認值。

5. processValidate:驗證攔截

  • 若 mapping.getValidate() == true 且 Form 實現 validate(),則執行驗證。

  • 驗證失敗 → 保存 ActionErrors 到請求 → 自動轉發到 mapping.getInput() 頁面。

  • 拋出 InvalidCancelException(用戶點擊取消)→ 走異常處理分支。

6. processForward / processInclude:配置級導航

  • 檢查 <action> 的 forward/include 屬性。

  • 優先 forward(RequestDispatcher.forward()),次之 include(include())。

  • 若配置則直接導航,不再執行 Action。

7. processActionCreate:Action 實例化(單例模式)

Action instance = null;
synchronized (actions) {
  instance = (Action) actions.get(className);
  if (instance != null) return instance;
  instance = (Action) RequestUtils.applicationInstance(className);  // 反射創建
  instance.setServlet(this.servlet);
  actions.put(className, instance);
}
return instance;
  • 每個 Action 類在模塊內單例,線程安全由開發者保證(Action 必須無狀態)。

8. processActionPerform:執行業務邏輯

try {
  return action.execute(mapping, form, request, response);
} catch (Exception e) {
  return processException(request, response, e, form, mapping);
}
  • 調用開發者覆寫的 execute()。

  • 異常統一交給 processException 記錄日志、構造錯誤轉發。

9. processForwardConfig:最終轉發

  • 解析 ActionForward.getPath()。

  • 以 / 開頭 → 模塊相對路徑,經 RequestUtils.forwardURL() 解析。

  • 否則視為絕對 URL。

  • 獲取 RequestDispatcher → forward()。

宏觀總結:七大階段

  1. 讀取配置:模塊、ActionMapping、Forward、DataSource 等。
  2. 獲取路徑:標準化請求路徑。
  3. 環境設置:Locale、Content-Type、緩存控制、消息清理。
  4. 表單處理:創建→填充→驗證(核心樣板邏輯)。
  5. 異常攔截:驗證取消、運行時異常統一處理。
  6. Action 執行:單例獲取→業務邏輯→返回 Forward。
  7. 結果轉發:Forward/Redirect/Include 完成響應。

擴展點與自定義

  • 繼承 RequestProcessor 覆寫任意 processXxx 方法,定制流程(如集成 Spring、添加權限檢查、修改驗證邏輯)。
  • PlugIn 在啟動/銷毀階段注入基礎設施(數據源、轉換器、調度器)。
  • 自定義 Action 基類 封裝通用業務邏輯(事務管理、日志、異常轉換)。

總結

RequestProcessor.process() 是 Struts 1 的「心臟」,以模板方法模式定義了請求處理的標準化流程。每個 processXxx 都是可覆寫的擴展點,框架使用者通過配置(struts-config.xml)和繼承(自定義 Processor/Action/Form)即可實現絕大多數 Web 應用需求,而無需修改框架核心代碼。深度理解這條鏈路,是排查疑難雜症、進行框架級優化、平滑遷移現代框架的關鍵基石。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved