struts可查看源码:https://github.com/apache/struts
在学习struts2之前,我先看了一些比较早版本对struts2的工作原理相关的介绍,顺便抄写过来,用来帮助自己要弄清这个框架的工作原理。
struts2.1.3之前使用的FilterDispatcher,之后的版本使用StrutsPrepareAndExecuteFilter,而我这里还是以Dispatcher为例来记录的。
依据:
Since Struts 2.1.3, use org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter instead or org.apache.struts2.dispatcher.ng.filter.StrutsPrepareFilter and org.apache.struts2.dispatcher.ng.filter.StrutsExecuteFilter if needing using the ActionContextCleanUp filter in addition to this one
To use a custom Dispatcher, the createDispatcher() method could be overriden by the subclass.
Version:$Date$ $Id$See Also:
ActionMapper
ActionContextCleanUp
org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter
org.apache.struts2.dispatcher.ng.filter.StrutsPrepareFilter
org.apache.struts2.dispatcher.ng.filter.StrutsExecuteFilter
下图描述了Struts2的工作原理:
一个请求在Struts2框架中的处理大致分为一下几个步骤:
1、客户端初始化一个纸箱Servlet容器(比如:Tomcat)的请求。
2、这个请求经过一系列的过滤器(Filter)。
备注:这些过滤器中有个叫做ActionContextCleanUp的可选过滤器,它对Struts2和其他框架的集成很有帮助。
3、接着FilterDispatcher被调用,FilterDispatcher询问ActoinMapper来决定这个请求是否需要调用某个Action。FilterDispatcher是控制器的核心,也是MVC的中C控制层的核心。请查看:《摘抄别人对FilterDispatcher工作流程和原理的分析:FilterDispatcher进行初始化并启用核心doFilter》。
4、如果ActionMapper决定要调用某个Action,FilterDispatcher把请求的处理交给ActoinProxy。
5、ActionProxy通过Configuration Manager询问框架配置文件,找到需要调用的Action类,一般是从structs.xml配置中读取。
6、ActionProxy创建一个ActionInvocation的实例。
7、ActoinInvocation实例使用命名模式来调用,在调用Action前后,设计到相关拦截器(Intercepter)的调用。
8、一旦Action执行完毕,ActionInvocation负责根据Struts.xml中的配置找到对应的返回结果。返回结果通常是(但不总是,也可能是另外的一个Action链)一个需要被表示的Jsp或者FreeMarker的模板。在表示的过程中可以使用Struts2框架中继承的标签。在这个过程中需要设计到ActionMapper。
在以上过程中所有的对象(Action,Results,Interceptors等)都是通过ObjectFactory来创建的。
- 下面我们来看看ActionInvocation是如何工作的:
ActionInvocation是Xworks 中Action 调度的核心。而对Interceptor 的调度,也正是由ActionInvocation负责。ActionInvocation 是一个接口,而DefaultActionInvocation 则是Webwork 对ActionInvocation的默认实现。
Interceptor的调度流程大致如下:
1.ActionInvocation初始化时,根据配置,加载Action相关的所有Interceptor。
2. 通过ActionInvocation.invoke方法调用Action实现时,执行Interceptor。
Interceptor将很多功能从我们的Action中独立出来,大量减少了我们Action的代码,独立出来的行为具有很好的重用性。XWork、WebWork的许多功能都是有Interceptor实现,可以在配置文件中组装Action用到的Interceptor,它会按照你指定的顺序,在Action执行前后运行。
这里,我们简单的介绍一下Interceptor
在struts2中自带了很多拦截器,在struts2-core-2.1.6.jar这个包下的struts-default.xml中我们可以发现:
1 <interceptors> 2 <interceptor name="alias"class="com.opensymphony.xwork2.interceptor.AliasInterceptor"/> 3 <interceptor name="autowiring"class="com.opensymphony.xwork2.spring.interceptor.ActionAutowiringInterceptor"/> 4 <interceptor name="chain"class="com.opensymphony.xwork2.interceptor.ChainingInterceptor"/> 5 <interceptor name="conversionError"class="org.apache.struts2.interceptor.StrutsConversionErrorInterceptor"/> 6 <interceptor name="clearSession"class="org.apache.struts2.interceptor.ClearSessionInterceptor"/> 7 <interceptor name="createSession"class="org.apache.struts2.interceptor.CreateSessionInterceptor"/> 8 <interceptor name="debugging"class="org.apache.struts2.interceptor.debugging.DebuggingInterceptor"/> 9 <interceptor name="externalRef"class="com.opensymphony.xwork2.interceptor.ExternalReferencesInterceptor"/> 10 <interceptor name="execAndWait"class="org.apache.struts2.interceptor.ExecuteAndWaitInterceptor"/> 11 <interceptor name="exception"class="com.opensymphony.xwork2.interceptor.ExceptionMappingInterceptor"/> 12 <interceptor name="fileUpload"class="org.apache.struts2.interceptor.FileUploadInterceptor"/> 13 <interceptor name="i18n"class="com.opensymphony.xwork2.interceptor.I18nInterceptor"/> 14 <interceptor name="logger"class="com.opensymphony.xwork2.interceptor.LoggingInterceptor"/> 15 <interceptor name="modelDriven"class="com.opensymphony.xwork2.interceptor.ModelDrivenInterceptor"/> 16 <interceptor name="scopedModelDriven"class="com.opensymphony.xwork2.interceptor.ScopedModelDrivenInterceptor"/> 17 <interceptor name="params"class="com.opensymphony.xwork2.interceptor.ParametersInterceptor"/> 18 <interceptor name="actionMappingParams"class="org.apache.struts2.interceptor.ActionMappingParametersInteceptor"/> 19 <interceptor name="prepare"class="com.opensymphony.xwork2.interceptor.PrepareInterceptor"/> 20 <interceptor name="staticParams"class="com.opensymphony.xwork2.interceptor.StaticParametersInterceptor"/> 21 <interceptor name="scope"class="org.apache.struts2.interceptor.ScopeInterceptor"/> 22 <interceptor name="servletConfig"class="org.apache.struts2.interceptor.ServletConfigInterceptor"/> 23 <interceptor name="sessionAutowiring"class="org.apache.struts2.spring.interceptor.SessionContextAutowiringInterceptor"/> 24 <interceptor name="timer"class="com.opensymphony.xwork2.interceptor.TimerInterceptor"/> 25 <interceptor name="token"class="org.apache.struts2.interceptor.TokenInterceptor"/> 26 <interceptor name="tokenSession"class="org.apache.struts2.interceptor.TokenSessionStoreInterceptor"/> 27 <interceptor name="validation"class="org.apache.struts2.interceptor.validation.AnnotationValidationInterceptor"/> 28 <interceptor name="workflow"class="com.opensymphony.xwork2.interceptor.DefaultWorkflowInterceptor"/> 29 <interceptor name="store"class="org.apache.struts2.interceptor.MessageStoreInterceptor"/> 30 <interceptor name="checkbox"class="org.apache.struts2.interceptor.CheckboxInterceptor"/> 31 <interceptor name="profiling"class="org.apache.struts2.interceptor.ProfilingActivationInterceptor"/> 32 <interceptor name="roles"class="org.apache.struts2.interceptor.RolesInterceptor"/> 33 <interceptor name="jsonValidation"class="org.apache.struts2.interceptor.validation.JSONValidationInterceptor"/> 34 <interceptorname="annotationWorkflow"class="com.opensymphony.xwork2.interceptor.annotations.AnnotationWorkflowInterceptor"/>
对于sturts2自带的拦截器,使用起来就相对比较方便了,我们只需要在struts.xml的action标签中加入<interceptor-ref name=" logger " />并且struts.xml扩展struts-default,就可以使用,
如果是要自定义拦截器,首先需要写一个拦截器的类:
1 package ceshi; 2 import com.opensymphony.xwork2.ActionInvocation; 3 import com.opensymphony.xwork2.interceptor.AbstractInterceptor; 4 5 publicclassAuthorizationInterceptor extends AbstractInterceptor { 6 7 @Override 8 public Stringintercept(ActionInvocation ai)throws Exception { 9 10 System.out.println("abc"); 11 return ai.invoke(); 12 13 } 14 15 }
并且在struts.xml中进行配置
1 <!DOCTYPEstruts PUBLIC 2 "-//Apache SoftwareFoundation//DTD Struts Configuration 2.0//EN" 3 "http://struts.apache.org/dtds/struts-2.0.dtd"> 4 5 6 <struts> 7 <package name="test"extends="struts-default"> 8 <interceptors> 9 <interceptor name="abc"class ="ceshi.AuthorizationInterceptor"/> 10 </interceptors> 11 <action name="TestLogger"class="vaannila.TestLoggerAction"> 12 <interceptor-refname="abc"/> 13 <result name="success">/success.jsp</result> 14 </action> 15 </package> 16 </struts>
- 摘抄别人对FilterDispatcher工作流程和原理的分析:FilterDispatcher进行初始化并启用核心doFilter
1 public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException ...{ 2 HttpServletRequest request = (HttpServletRequest) req; 3 HttpServletResponse response = (HttpServletResponse) res; 4 ServletContext servletContext = filterConfig.getServletContext(); 5 // 在这里处理了HttpServletRequest和HttpServletResponse。 6 DispatcherUtils du = DispatcherUtils.getInstance(); 7 du.prepare(request, response);//正如这个方法名字一样进行locale、encoding以及特殊request parameters设置 8 try ...{ 9 request = du.wrapRequest(request, servletContext);//对request进行包装 10 } catch (IOException e) ...{ 11 String message = "Could not wrap servlet request with MultipartRequestWrapper!"; 12 LOG.error(message, e); 13 throw new ServletException(message, e); 14 } 15 ActionMapperIF mapper = ActionMapperFactory.getMapper();//得到action的mapper 16 ActionMapping mapping = mapper.getMapping(request);// 得到action 的 mapping 17 if (mapping == null) ...{ 18 // there is no action in this request, should we look for a static resource? 19 String resourcePath = RequestUtils.getServletPath(request); 20 if ("".equals(resourcePath) && null != request.getPathInfo()) ...{ 21 resourcePath = request.getPathInfo(); 22 } 23 if ("true".equals(Configuration.get(WebWorkConstants.WEBWORK_SERVE_STATIC_CONTENT)) 24 && resourcePath.startsWith("/webwork")) ...{ 25 String name = resourcePath.substring("/webwork".length()); 26 findStaticResource(name, response); 27 } else ...{ 28 // this is a normal request, let it pass through 29 chain.doFilter(request, response); 30 } 31 // WW did its job here 32 return; 33 } 34 Object o = null; 35 try ...{ 36 //setupContainer(request); 37 o = beforeActionInvocation(request, servletContext); 38 //整个框架最最核心的方法,下面分析 39 du.serviceAction(request, response, servletContext, mapping); 40 } finally ...{ 41 afterActionInvocation(request, servletContext, o); 42 ActionContext.setContext(null); 43 } 44 } 45 du.serviceAction(request, response, servletContext, mapping); 46 //这个方法询问ActionMapper是否需要调用某个Action来处理这个(request)请求,如果ActionMapper决定需要调用某个Action,FilterDispatcher把请求的处理交给ActionProxy 47 48 public void serviceAction(HttpServletRequest request, HttpServletResponse response, String namespace, String actionName, Map requestMap, Map parameterMap, Map sessionMap, Map applicationMap) ...{ 49 HashMap extraContext = createContextMap(requestMap, parameterMap, sessionMap, applicationMap, request, response, getServletConfig()); //实例化Map请求 ,询问ActionMapper是否需要调用某个Action来处理这个(request)请求 50 extraContext.put(SERVLET_DISPATCHER, this); 51 OgnlValueStack stack = (OgnlValueStack) request.getAttribute(ServletActionContext.WEBWORK_VALUESTACK_KEY); 52 if (stack != null) ...{ 53 extraContext.put(ActionContext.VALUE_STACK,new OgnlValueStack(stack)); 54 } 55 try ...{ 56 ActionProxy proxy = ActionProxyFactory.getFactory().createActionProxy(namespace, actionName, extraContext); 57 //这里actionName是通过两道getActionName解析出来的, FilterDispatcher把请求的处理交给ActionProxy,下面是ServletDispatcher的 TODO: 58 request.setAttribute(ServletActionContext.WEBWORK_VALUESTACK_KEY, proxy.getInvocation().getStack()); 59 proxy.execute(); 60 //通过代理模式执行ActionProxy 61 if (stack != null)...{ 62 request.setAttribute(ServletActionContext.WEBWORK_VALUESTACK_KEY,stack); 63 } 64 } catch (ConfigurationException e) ...{ 65 log.error("Could not find action", e); 66 sendError(request, response, HttpServletResponse.SC_NOT_FOUND, e); 67 } catch (Exception e) ...{ 68 log.error("Could not execute action", e); 69 sendError(request, response, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e); 70 } 71 }
- FilterDispatcher作用
Master filter for Struts that handles four distinct responsibilities:
•Executing actions
•Cleaning up the ActionContext (see note)
•Serving static content
•Kicking off XWork's interceptor chain for the request lifecycle
IMPORTANT: this filter must be mapped to all requests. Unless you know exactly what you are doing, always map to this URL pattern: /*
Executing actions
This filter executes actions by consulting the ActionMapper and determining if the requested URL should invoke an action. If the mapper indicates it should, the rest of the filter chain is stopped and the action is invoked. This is important, as it means that filters like the SiteMesh filter must be placed before this filter or they will not be able to decorate the output of actions.
Cleaning up the ActionContext
This filter will also automatically clean up the ActionContext for you, ensuring that no memory leaks take place. However, this can sometimes cause problems integrating with other products like SiteMesh. See ActionContextCleanUp for more information on how to deal with this.
Serving static content
This filter also serves common static content needed when using various parts of Struts, such as JavaScript files, CSS files, etc. It works by looking for requests to /struts/*, and then mapping the value after "/struts/" to common packages in Struts and, optionally, in your class path. By default, the following packages are automatically searched:
•org.apache.struts2.static
•template
This means that you can simply request /struts/xhtml/styles.css and the XHTML UI theme's default stylesheet will be returned. Likewise, many of the AJAX UI components require various JavaScript files, which are found in the org.apache.struts2.static package. If you wish to add additional packages to be searched, you can add a comma separated (space, tab and new line will do as well) list in the filter init parameter named "packages". Be careful, however, to expose any packages that may have sensitive information, such as properties file with database access credentials.
This filter supports the following init-params:
•config - a comma-delimited list of XML configuration files to load.
•actionPackages - a comma-delimited list of Java packages to scan for Actions.
•configProviders - a comma-delimited list of Java classes that implement the ConfigurationProvider interface that should be used for building the Configuration.
•loggerFactory - The class name of the LoggerFactory implementation.
•* - any other parameters are treated as framework constants.
参考:http://blog.csdn.net/laner0515/article/details/27692673/