上篇讲了Tomcat实例化一个单例的ActionServlet。依据web.xml配置文件做好对应的初始化工作。
这时client产生一个.do结尾的request请求,採用get/post方式提交之后。不论哪种方式提交,都会进入到process核心方法中。
      public void <strong>doGet</strong>(HttpServletRequest request,	HttpServletResponse response)
	        throws IOException, ServletException {
	
	        <strong>process</strong>(request, response);
	
	    }
	
	
	    public void <strong>doPost</strong>(HttpServletRequest request,      HttpServletResponse response)
	        throws IOException, ServletException {
	
	        <strong>process</strong>(request, response);
	
	    }
	    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);
	
	    }
  首先调用org.apache.struts.util.ModuleUtils类的selectModule()方法。这种方法依据请求对象和servletContext选择负责处理当前请求所属的模块。然后把与该模块相关的ModuleConfig和MessageResources对象存储倒request范围中,这使得框架的其余组件能够方便地从request范围中读取这些对象,从而获取应用配置信息和消息资源。
  其次, 实例化RequestProcessor类。然后调用RequestProcessor类的process()方法,来完毕十几的预处理请求操作。
public void process(HttpServletRequest request,                        HttpServletResponse response)
        throws IOException, ServletException {
        // Wrap multipart requests with a special wrapper
        request = processMultipart(request);
        // Identify the path component we will use to select a mapping
        String path = processPath(request, response);
        if (path == null) {
            return;
        }
        
        if (log.isDebugEnabled()) {
            log.debug("Processing a '" + request.getMethod() +
                      "' for path '" + path + "'");
        }
        // Select a Locale for the current user if requested
        processLocale(request, response);
        // Set the content type and no-caching headers if requested
        processContent(request, response);
        processNoCache(request, response);
        // General purpose preprocessing hook
        if (!processPreprocess(request, response)) {
            return;
        }
        
        this.processCachedMessages(request, response);
        // Identify the mapping for this request
        ActionMapping mapping = processMapping(request, response, path);
        if (mapping == null) {
            return;
        }
        // Check for any role required to perform this action
        if (!processRoles(request, response, mapping)) {
            return;
        }
        // Process any ActionForm bean related to this request
        ActionForm form = processActionForm(request, response, mapping);
        processPopulate(request, response, form, mapping);
        
        // Validate any fields of the ActionForm bean, if applicable
        try {
            if (!processValidate(request, response, form, mapping)) {
                return;
            }
        } catch (InvalidCancelException e) {
            ActionForward forward = processException(request, response, e, form, mapping);
            processForwardConfig(request, response, forward);
            return;
        } catch (IOException e) {
            throw e;
        } catch (ServletException e) {
            throw e;
        }
            
        // Process a forward or include specified by this mapping
        if (!processForward(request, response, mapping)) {
            return;
        }
        
        if (!processInclude(request, response, mapping)) {
            return;
        }
        // Create or acquire the Action instance to process this request
        Action action = processActionCreate(request, response, mapping);
        if (action == null) {
            return;
        }
        // Call the Action instance itself
        ActionForward forward =
            processActionPerform(request, response,
                                 action, form, mapping);
        // Process the returned ActionForward instance
        processForwardConfig(request, response, forward);
    }
依照process()方法的运行流程,
	if (!"POST".equalsIgnoreCase(request.getMethod())) {
		return (request);
        }
2、获取request对象的ContentType,假设ContentType为multipart/form-datade 话则 new 一个 MultipartRequestWrapper 对象返回。
否则直接返回request。
 String contentType = request.getContentType();        if ((contentType != null)
            && contentType.startsWith("multipart/form-data")) {
            return (new MultipartRequestWrapper(request));
        } else {
            return (request);
        }
        String path = processPath(request, response);
        if (path == null) {
            return;
        }        
        if (log.isDebugEnabled()) {
            log.debug("Processing a '" + request.getMethod() +
                      "' for path '" + path + "'");
        }
   通过调用processPath方法。获得訪问的详细action的名字
protected void processLocale(HttpServletRequest request,HttpServletResponse response) {
	
	        // Are we configured to select the Locale automatically?
	        if (!moduleConfig.getControllerConfig().getLocale()) {
	            return;
	        }
	        // Has a Locale already been selected?
	        HttpSession session = request.getSession();
	        if (session.getAttribute(Globals.LOCALE_KEY) != null) {
	            return;
	        }
	        // Use the Locale returned by the servlet container (if any)
	        Locale locale = request.getLocale();
	        if (locale != null) {
	            if (log.isDebugEnabled()) {
	                log.debug(" Setting user locale '" + locale + "'");
	            }
	            session.setAttribute(Globals.LOCALE_KEY, locale);
	        }
	    }
   
是本地服务还是国际化服务,这是依据浏览器的设置的(确切的说是依据操作系统设置的)
   当中processContent用来确定内容类型和编码类型
   processNoCache依据配置文件里的配置属性来确定某些内容是否进行缓存
   依据request。response和action的名字去Struts.config.xml中获取相应的actionmapping,也就是将我们配置好的request要请求的action放入到ActionMapping对象中去。
1、首先去配置文件中找对应的配置信息
// Is there a mapping for this path?ActionMapping mapping = (ActionMapping) moduleConfig.findActionConfig(path);
2、假设有配置则把它放入request。并返回。
        // If a mapping is found, put it in the request and return it
        if (mapping != null) {
            request.setAttribute(Globals.MAPPING_KEY, mapping);
            return (mapping);
        }
3、找到“未知的映射路径(假设有的话)”。相同找到了就放到request里并返回他。
        // Locate the mapping for unknown paths (if any)
        ActionConfig[] configs = moduleConfig.findActionConfigs();
        for (int i = 0; i < configs.length; i++) {
            if (configs[i].getUnknown()) {
                mapping = (ActionMapping) configs[i];
                request.setAttribute(Globals.MAPPING_KEY, mapping);
                return (mapping);
            }
        }
4、假设还是没有找到mapping信息则发送错误消息。并返回null
        // No mapping can be found to process this request
        String msg = getInternal().getMessage("processInvalid");
        log.error(msg + " " + path);
        response.sendError(HttpServletResponse.SC_NOT_FOUND, msg);
        return null;此时。ActionMapping元素包括了如Action类的名称及在请求中用到的ActionForm的信息,另外还有配置在当前ActionMapping的里的ActionForwards信息。
	 protected ActionForm processActionForm(HttpServletRequest request,
	                                           HttpServletResponse response,
	                                           ActionMapping mapping) {
	
	        // Create (if necessary) a form bean to use
	        ActionForm instance = RequestUtils.createActionForm
	            (request, mapping, moduleConfig, servlet);
	        if (instance == null) {
	            return (null);
	        }
	
	        // Store the new instance in the appropriate scope
	        if (log.isDebugEnabled()) {
	            log.debug(" Storing ActionForm bean instance in scope '" +
	                mapping.getScope() + "' under attribute key '" +
	                mapping.getAttribute() + "'");
	        }
	        if ("request".equals(mapping.getScope())) {
	            request.setAttribute(mapping.getAttribute(), instance);
	        } else {
	            HttpSession session = request.getSession();
	            session.setAttribute(mapping.getAttribute(), instance);
	        }
	        return (instance);
	
	    }
 protected void processPopulate(HttpServletRequest request,
                                   HttpServletResponse response,
                                   ActionForm form,
                                   ActionMapping mapping)
        throws ServletException {
        if (form == null) {
            return;
        }
        // Populate the bean properties of this ActionForm instance
        if (log.isDebugEnabled()) {
            log.debug(" Populating bean properties from this request");
        }        
        form.setServlet(this.servlet);
        form.reset(mapping, request);
        
        if (mapping.getMultipartClass() != null) {
            request.setAttribute(Globals.MULTIPART_KEY,
                                 mapping.getMultipartClass());
        }        
        RequestUtils.populate(form, mapping.getPrefix(), mapping.getSuffix(),
                              request);
        // Set the cancellation request attribute if appropriate
        if ((request.getParameter(Constants.CANCEL_PROPERTY) != null) ||
            (request.getParameter(Constants.CANCEL_PROPERTY_X) != null)) {                
            request.setAttribute(Globals.CANCEL_KEY, Boolean.TRUE);
        }
    }
验证表单数据合法性,这个可用可不用的。假设使用了Struts的验证,这里会自己主动的运行该方法进行验证。
   处理mapping指定的forward 和 include,Struts检查<action>元素的forward和include属性的值。假如有配置。则把forward和include 请求放在配置的页面内,之后转发到详细的ActionServlet中进行详细业务逻辑的处理。
至此,RequestProcessor的核心方法process运行完成。之后会到详细的Action中运行业务相关的操作。
纵观整个运行流程,其基本的方法无外乎两个,一个是AcionServlet中的process方法,还有一个是RequestProcessor的process()方法,至于其它的截取请求路径,填充actionForm。国际化等方法也都被用于外观模式封装在了process方法中。
SSH框架之Struts(3)——Struts的执行流程之核心方法
原文:http://www.cnblogs.com/cynchanpin/p/7130344.html