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。