It takes some time to look at the struts2 source code. From today on, let's make a summary.
First, let's take a look at how to debug the struts2 source code. The main steps are as follows:
Use myeclipse to create a web project
Import the jar package required by struts2
Associate the jar package with the source file
Right-click the jar package in and choose Properties> JAVA source attach. If the association is successful, double-click a class file under the jar package to display the Java source code.
Double-click the. Class file and set the breakpoint in the key part of the source code.
Deploy the project to Tomcat
Tomcat is started in debug mode
After the preceding steps, you can perform one-step debugging to conveniently view the code running status.
As the MVC Framework, the struts2 framework is mainly used to help process requests in a way unrelated to Web containers. That is to say, you can not use classes such as httpservletrequest when processing requests. Struts2 uses filters to intercept requests. If struts2 can process the requests, the requests will go to the struts2 framework for processing. Otherwise, the requests will go to the next filter.
Let's take a look at struts2 from the beginning of filter initialization, because this is also the initialization process of the struts2 framework.
OK. Let's take a look at the init () method of the strutsprepareandexecutefilter class in struts2:
Public void Init (filterconfig) throws servletexception {initoperations init = new initoperations (); dispatcher = NULL; try {filterhostconfig config Config = new filterhostconfig (filterconfig ); // only a thin layer of init is encapsulated. initlogging (config); // initialize the logger dispatcher = init. initdispatcher (config); // create a forwarder and initialize init. initstaticcontentloader (config, dispatcher); // initialize the static resource loader Prepa Re = new prepareoperations (filterconfig. getservletcontext (), dispatcher); execute = new executeoperations (filterconfig. getservletcontext (), dispatcher); this. excludedpatterns = init. buildexcludedpatternslist (dispatcher); postinit (dispatcher, filterconfig);} finally {If (dispatcher! = NULL) {dispatcher. cleanupafterinit () ;}init. Cleanup ();}}
From the code above, we can conclude that initialization mainly completes the following tasks:
1. encapsulate the init () parameter filterconfig into the filterhostconfig defined by struts2
The Code is as follows:
public class FilterHostConfig implements HostConfig { private FilterConfig config; public FilterHostConfig(FilterConfig config) { this.config = config; } public String getInitParameter(String key) { return config.getInitParameter(key); } public Iterator<String> getInitParameterNames() { return MakeIterator.convert(config.getInitParameterNames()); } public ServletContext getServletContext() { return config.getServletContext(); }}
2. initialize the logger. If the loggerfactory parameter is configured when the filter is configured in Web. XML
Initlogging () through the initoperations class (). The initoperations class encapsulates some initialization operations. The following describes all the methods of the class. The functions of the method can also be seen from the name.
public class InitOperations { public InitOperations() public void initLogging( HostConfig filterConfig ) public Dispatcher initDispatcher( HostConfig filterConfig ) public StaticContentLoader initStaticContentLoader( HostConfig filterConfig, Dispatcher dispatcher ) public Dispatcher findDispatcherOnThread() private Dispatcher createDispatcher( HostConfig filterConfig ) public void cleanup() public List<Pattern> buildExcludedPatternsList( Dispatcher dispatcher ) private List<Pattern> buildExcludedPatternsList( String patterns )}
3. Create a dispatcher and initialize it.
Dispatcher is an important class in struts2. It transfers the requests intercepted by the filter to the request processing module of struts2. Of course, the dispatcher will be initialized first, and its initialization method Init () does a lot of work. This part will be explained in detail later. Let's take a look at the process. In the initoperations class:
public Dispatcher initDispatcher( HostConfig filterConfig ) { Dispatcher dispatcher = createDispatcher(filterConfig); dispatcher.init(); return dispatcher; }
private Dispatcher createDispatcher( HostConfig filterConfig ) { Map<String, String> params = new HashMap<String, String>(); for ( Iterator e = filterConfig.getInitParameterNames(); e.hasNext(); ) { String name = (String) e.next(); String value = filterConfig.getInitParameter(name); params.put(name, value); } return new Dispatcher(filterConfig.getServletContext(), params); }
Here, the filter configuration parameters are saved as in the dispatcher object. The configuration is as follows:
<filter> <filter-name>struts2</filter-name> <filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class> <init-param> <param-name>filterParam</param-name> <param-value>abc</param-value> </init-param> </filter>
4. initialize the static resource loader.
public StaticContentLoader initStaticContentLoader( HostConfig filterConfig, Dispatcher dispatcher ) { StaticContentLoader loader = dispatcher.getContainer().getInstance(StaticContentLoader.class); loader.setHostConfig(filterConfig); return loader; }
After dispatcher initialization, a container maintained by struts2 is created and can be used. Create a staticcontentloader object through container.
Staticcontentloader is an interface to see which methods are declared by this interface:
public interface StaticContentLoader { public boolean canHandle(String path); public abstract void setHostConfig(HostConfig filterConfig); public abstract void findStaticResource(String path, HttpServletRequest request, HttpServletResponse response) throws IOException;}
Struts2 has an implementation class defaultstaticcontentloader. In general, struts2 does not process requests for static resources unless the request path starts with Struts or static. If there is a test application, the request must be/test/struts /... or/test/static /... this will be handled.
If the struts2 framework does not process static resource requests, who will handle them? Naturally, it is a Web container, such as Tomcat. In strutsprepareandexecutefilter:
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {<span style="white-space:pre"></span>... ActionMapping mapping = prepare.findActionMapping(request, response, true); if (mapping == null) { boolean handled = execute.executeStaticResourceRequest(request, response); if (!handled) { chain.doFilter(request, response); } } else { execute.executeAction(request, response, mapping); } ... }
We can see that if the request is not processed, call chain. dofilter () and the request will not enter the struts2 framework.
So what should we do if we want the struts2 framework to process such a request?
First, the request path must start with Struts or static.
Then, static resources should be stored in one of the following packages of the application:
Struts
Org. Apache. struts2.static
Template
Org. Apache. struts2.interceptor. debugging
You can also specify the package name in the filter configuration parameter:
<init-param> <param-name>packages</param-name> <param-value>abc</param-value></init-param>
If multiple packages exist, separate them with commas.
In this case.
5. Create prepareoperations objects and executeoperations objects
What are the functions of prepareoperations and executeoperations? Similar to initoperations, it encapsulates some operations. However, initoperations encapsulate initialization operations, while the first two are encapsulation Request preprocessing and request processing operations. when processing a request, the method is called. First, let's take a look at the operations of prepareoperations:
public class PrepareOperations { public PrepareOperations(ServletContext servletContext, Dispatcher dispatcher) public ActionContext createActionContext(HttpServletRequest request, HttpServletResponse response) public void cleanupRequest(HttpServletRequest request) public void assignDispatcherToThread() public void setEncodingAndLocale(HttpServletRequest request, HttpServletResponse response) public HttpServletRequest wrapRequest(HttpServletRequest oldRequest) public ActionMapping findActionMapping (HttpServletRequest request, HttpServletResponse response) public ActionMapping findActionMapping(HttpServletRequest request, HttpServletResponse response, boolean forceLookup) public void cleanupDispatcher() public boolean isUrlExcluded( HttpServletRequest request, List<Pattern> excludedPatterns ) private String getUri( HttpServletRequest request )}
Executeoperations is much simpler:
public class ExecuteOperations { private ServletContext servletContext; private Dispatcher dispatcher; public ExecuteOperations(ServletContext servletContext, Dispatcher dispatcher) { this.dispatcher = dispatcher; this.servletContext = servletContext; } /** * Tries to execute a request for a static resource * @return True if it was handled, false if the filter should fall through * @throws IOException * @throws ServletException */ public boolean executeStaticResourceRequest(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { // there is no action in this request, should we look for a static resource? String resourcePath = RequestUtils.getServletPath(request); if ("".equals(resourcePath) && null != request.getPathInfo()) { resourcePath = request.getPathInfo(); } StaticContentLoader staticResourceLoader = dispatcher.getContainer().getInstance(StaticContentLoader.class); if (staticResourceLoader.canHandle(resourcePath)) { staticResourceLoader.findStaticResource(resourcePath, request, response); // The framework did its job here return true; } else { // this is a normal request, let it pass through return false; } } /** * Executes an action * @throws ServletException */ public void executeAction(HttpServletRequest request, HttpServletResponse response, ActionMapping mapping) throws ServletException { dispatcher.serviceAction(request, response, servletContext, mapping); }}
The processing of requests will be detailed later. Let's take it as a warm-up.
6. encapsulate the pattern of the unprocessed action request specified during filter configuration to list <pattern>
This configuration is set through the constant struts_action_exclude_pattern. In the Struts. xml or struts. properties file.
7. Complete cleaning
In fact, we haven't cleared much.
OK. The basic initialization process is analyzed, but the dispatcher Initialization is still a black box. So the next article will detail the dispatcher initialization.