This blog goes deep into the Struts framework to execute some source code. Starting from the actionservlet process function, let's take a look at its internal execution process.
Flowchart
The following flowchart shows the functions used by the actionservlet and requestprocessor classes. For example, the functions of other classes called by requestprocessor are not described.
Function Description
Let's select several important function descriptions, while other functions can be simply described.
Actionservlet Process
/** * <p>Perform the standard request processing for this request, and create * the corresponding response.</p> * * @param request The servlet request we are processing * @param response The servlet response we are creating * * @exception IOException if an input/output error occurs * @exception ServletException if a servlet exception is thrown */ 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); }}
During debugging, you must first enter this function (after Tomcat is started and a request is generated). This function is used to obtain the module object generated in the loading phase and generate the main object requestprocessor for struts logic processing.
Requestprocessor Process
/** * <p>Process an <code>HttpServletRequest</code> and create the * corresponding <code>HttpServletResponse</code> or dispatch * to another resource.</p> * * @param request The servlet request we are processing * @param response The servlet response we are creating * * @exception IOException if an input/output error occurs * @exception ServletException if a processing exception occurs */ 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 is the main logical processing function of the requestprocessor object. According to the flowchart above, we can see that the entire logical processing is completed in this function. The functions of the called function are as follows:
Processmultipart
This function is used to determine whether it is a file upload request. If it is a file upload request, it is specially processed.
/** * <p>If this is a multipart request, wrap it with a special wrapper. * Otherwise, return the request unchanged.</p> * * @param request The HttpServletRequest we are processing */ 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)); } else { return (request); } }
Processpath
Obtain and intercept the request. After processing, the request becomes a required string, for example, http: // localhost: 8080/struts_login/login. Do. The processed string is/login. Do.
/** * <p>Identify and return the path component (from the request URI) that * we will use to select an <code>ActionMapping</code> with which to dispatch. * If no such path can be identified, create an error response and return * <code>null</code>.</p> * * @param request The servlet request we are processing * @param response The servlet response we are creating * * @exception IOException if an input/output error occurs */ protected String processPath(HttpServletRequest request, HttpServletResponse response) throws IOException { String path = null; // For prefix matching, match on the path info (if any) path = (String) request.getAttribute(INCLUDE_PATH_INFO); if (path == null) { path = request.getPathInfo(); } if ((path != null) && (path.length() > 0)) { return (path); } // For extension matching, strip the module prefix and extension path = (String) request.getAttribute(INCLUDE_SERVLET_PATH); if (path == null) { path = request.getServletPath(); } String prefix = moduleConfig.getPrefix(); if (!path.startsWith(prefix)) { String msg = getInternal().getMessage("processPath"); log.error(msg + " " + request.getRequestURI()); response.sendError(HttpServletResponse.SC_BAD_REQUEST, msg); return null; } path = path.substring(prefix.length()); int slash = path.lastIndexOf("/"); int period = path.lastIndexOf("."); if ((period >= 0) && (period > slash)) { path = path.substring(0, period); } return (path); }
Set related functions
Processlocale, processcontent, processnocache, and processcachedmessages are used to set up international files, set content types, cancel cache settings, and clear struts error information in sessions.
Processmapping
Instantiate the corresponding actionmapping object based on the path generated above. If this object is not empty, it is loaded into the request and the corresponding name is globals. mapping_key. If it is null, an exception is sent and added to response.
// If a mapping is found, put it in the request and return it if (mapping != null) { request.setAttribute(Globals.MAPPING_KEY, mapping); return (mapping); } // 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); } }
Processroles
Whether action execution requires specific role permissions. If not, continue execution.
String roles[] = mapping.getRoleNames(); if ((roles == null) || (roles.length < 1)) { return (true); }
Processactionform
Create an actionform and check the action scope. If it is a request, it is added to the request. If it is a session, it is added to the session.
// 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); }
Actionform Problems
Processpopulate: calls the processpopulate () method. If there is an actionform configured for actionmapping, it encapsulates the data in the request object to actionform.
Before encapsulation, call the reset () method of actionform to set the default attribute values.
Processvalidate: If the attribute validate of the action element is set to true, The Validate () method is called for rule verification. If the validate () method validation fails, an actionerrors
In the request area, the request is automatically redirected to the page specified by the INPUT attribute mapped to the action. If the verification is passed or the actionform is not configured in the Action ing, the request is processed.
Exception Handling
The process function contains a try... Catch Block. If invalidcancelexception occurs, two functions are executed.
Processexception: writes the exception to the Log Warning file and runs out of the exception. processforwardconfig is the same as the last function executed below, and the capture ends.
Jump path
Processforward and processinclude: these two functions are used to check the values of the forward and include attributes of the <action> element in Struts-config. If there is a configuration, forward and include
The request is placed on the configuration page. processforward () calls requestdispatcher. Forward (), while processinclude () calls requestdispatcher. Include ().
If both the forward and include attributes are configured, Struts gives priority to forward.
Processactioncreate
This function obtains the action class name from the type attribute of <action> In Struts-config, and creates and returns its instance.
Action instance = null; synchronized (actions) { // Return any existing Action instance of this class instance = (Action) actions.get(className); if (instance != null) { if (log.isTraceEnabled()) { log.trace(" Returning existing Action instance"); } return (instance); } // Create and return a new Action instance if (log.isTraceEnabled()) { log.trace(" Creating new Action instance"); } try { instance = (Action) RequestUtils.applicationInstance(className); // :TODO: Maybe we should propagate this exception // instead of returning null. } catch (Exception e) { log.error( getInternal().getMessage("actionCreate", mapping.getPath()), e); response.sendError( HttpServletResponse.SC_INTERNAL_SERVER_ERROR, getInternal().getMessage("actionCreate", mapping.getPath())); return (null); } instance.setServlet(this.servlet); actions.put(className, instance); } return (instance);
Processactionperform
Execute the Execute function in the Self-written action, including the jump logic:
try { return (action.execute(mapping, form, request, response)); } catch (Exception e) { return (processException(request, response, e, form, mapping)); }
Processforwardconfig:
String forwardPath = forward.getPath(); String uri = null; // paths not starting with / should be passed through without any processing // (ie. they're absolute) if (forwardPath.startsWith("/")) { uri = RequestUtils.forwardURL(request, forward, null); // get module relative uri } else { uri = forwardPath; }
Doforward obtains requestdispatcher and performs a jump.
if (request instanceof MultipartRequestWrapper) { request = ((MultipartRequestWrapper) request).getRequest(); } RequestDispatcher rd = getServletContext().getRequestDispatcher(uri); if (rd == null) { response.sendError( HttpServletResponse.SC_INTERNAL_SERVER_ERROR, getInternal().getMessage("requestDispatcher", uri)); return; } rd.forward(request, response);
Summary
If we ignore the function, we can summarize it from a macro perspective as follows:
- Read configuration files
- Get access address
- Set struts
- Create, assign, and verify actionform
- Exception Handling
- Create action
- Execute the logic in the action
- Page Jump
So far, if you do not investigate the underlying function, the struts execution process has been explained. If you have any questions, please note.
For more related blogs, go to the Summary of progressive struts1 (8)