ActionServlet類是Struts架構的內建核心控制器組件,它繼承了javax.servlet.http.HttpServlet類。Struts的啟動通常從
載入ActionServlet開始。Web容器會在初次開機或Struts應用的第一個請求到達時載入ActionServlet。一般情況下都
配置web容器比如tomcat啟動的時候載入ActionServlet類,使用<load-on-startup>1</load-on-startup>標籤配置啟動
載入。
ActionServlet有如下這幾個功能
1:讀取設定檔Struts-config.xml
ActionServlet載入的時候讀取Struts-config.xml檔案,將檔案對應的配置資訊讀取到記憶體中,ActionServlet 根據不同的模組來初始化 ModuleConfig 類,並在其中以XXXconfig 集合的方式儲存該模組的各種配置資訊,比如 ActionConfig,FormBeanConfig 等。
比如設定檔中的 Action映射定義都儲存在 ActionConfig 集合中。相應地有 ControlConfig 集合、FormBeanConfig 集合、ForwardConfig集合和 MessageResourcesConfig 集合等。
這裡的模組是為了用於不同使用者在同時使用struts-config.xml檔案時衝突,每個使用者可以定義自己的設定檔,由容器自動去整合配置,每個設定檔相當於一個模組。
2:截取用戶端http請求,分發到相應的Action
初始化工作完成之後,ActionServlet準備接收客戶請求。針對每個請求,方法 process(HttpServletRequest request, HttpServletResponseresponse) 將被調用。該方法指定具體的模組,然後調用該模組的 RequestProcessor 的 process 方法。
其實根據Servlet的原理,應該調用ActionServlet的doPost()或doGet()方法來處理使用者請求,而它們實際上都是調用process()方法具體處理請求的,如下列代碼:
public void doGet(HttpServletRequest request,HttpServletResponse response) throws IOException, ServletException { process(request, response); }
public void doPost(HttpServletRequest request,HttpServletResponse response) throws IOException, ServletException { process(request, response); }
protected void process(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { //根據請求選擇適當的應用模組 ModuleUtils.getInstance().selectModule(request, getServletContext()); ModuleConfig config = getModuleConfig(request);//擷取模組相關的RequestProcesser執行個體 RequestProcessor processor = getProcessorForModule(config); if (processor == null) { processor = getRequestProcessor(config); } //調用processor執行個體的process()方法處理請求 processor.process(request, response); }
在上面我們看到ActionServlet的process()方法中實際處理使用者請求的是RequestProcessor類的process()方法。Struts架構只允許應用程式中存在一個ActionServlet類,但每個應用程式模組都有各自的RequestProcessor類執行個體。在ActionServlet的process()方法中,一旦選擇了正確的應用程式模組,就會調用相應模組RequestProcessor執行個體的process()方法來處理請求。RequestProcessor類的process方法如下:
//摘自RequestProcessor public void process(HttpServletRequest request, HttpServletResponse response)throws IOException, ServletException { //用一個特殊的封裝對象把Muiltipart請求封裝起來 request = processMultipart(request); //驗證我們用來選擇映射的路徑組件 String path = processPath(request, response); if (path != null) { if (log.isDebugEnabled()) log.debug("Processing a '" + request.getMethod() + "' for path '" + path + "'"); //有請求時, 為目前使用者選擇一個Locale對象 processLocale(request, response); //有請求時,設定內容類型和no-caching字頭 processContent(request, response); processNoCache(request, response); if (processPreprocess(request, response)) { processCachedMessages(request, response); //驗證這個請求的映射 ActionMapping mapping = processMapping(request, response, path); if (mapping != null && processRoles(request, response, mapping)) { //處理和這個請求相關的任何ActionForm bean ActionForm form = processActionForm(request, response, mapping); processPopulate(request, response, form, mapping); if (processValidate(request, response, form, mapping)&& processForward(request, response, mapping)&& processInclude(request, response, mapping)) { //建立或擷取Action執行個體來處理這項請求 Action action = processActionCreate(request, response, mapping); if (action != null) { //調用Action執行個體本身 ActionForward forward = processActionPerform(request, response,action, form, mapping); //處理所返回的ActionForward執行個體 processForwardConfig(request, response, forward); } } } } } }
ActionServlet在 ActionConfig 中找出對應於該請求的 Action 子類,如果沒有對應的 Action,控制器直接將請求轉寄給 JSP或者靜態頁面。否則控制器將請求分發至具體 Action 類進行處理。
3:從請求中擷取資料填充 FormBean(如果需要)
在控制器調用具體 Action 的 execute方法之前,ActionForm 對象將利用 HTTP 要求中的參數來填充自己(可選步驟,需要在設定檔中指定)。具體的 ActionForm 對象應該是ActionForm 的子類對象,它其實就是一個 JavaBean。
需要特別說明的是,Struts的設定檔struts-config.xml作為ActionServlet的一個初始化參數值在web.xml檔案中聲明。另外,ActionServlet的URL形式是*.do,這樣當在瀏覽器地址輸入任何尾碼為*.do的URL時,系統都會映射到ActionServlet。