struts2 流程 简单描述

1、整体结构

  

2.几个概念

2.1 actionContext:  is the context in which an Action is executed. Each context is basically a container of objects an action needs for execution like the session, parameters, locale, etc.

    保存session,parameters等对象的是一个Map类型叫context对象。 其在内存中的快照如下:

 2.2 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

Struts2.1.3之后用StrutsPrepareAndExecuteFilter 替换

 

2.3 Dsipatcher:

      struts真正用来转发的类。

     该类是线程安全的。因为它的实例是如下代码生成的   

1 private static ThreadLocal<Dispatcher> instance = new ThreadLocal<Dispatcher>();
2   
3 public static Dispatcher getInstance() {
4     return instance.get();
5 }

     用来处理的方法是serviceAction

1 public void serviceAction(HttpServletRequest request, HttpServletResponse response, ServletContext context,
2                               ActionMapping mapping) throws ServletException

与Action相关的信息如name result path 在ActionMapping中。ActionMapping 的定义

1 public class ActionMapping {
2     private String name;
3     private String namespace;
4     private String method;
5     private String extension;
6     private Map<String, Object> params;
7     private Result result;

2.4 ActionInvocation:如何创建,执行Action。实现类DefaultActionInvocation。包含的对象有

01 protected Object action;
02     protected ActionProxy proxy;
03     protected List<PreResultListener> preResultListeners;
04     protected Map<String, Object> extraContext;
05     protected ActionContext invocationContext;
06     protected Iterator<InterceptorMapping> interceptors;
07     protected ValueStack stack;
08     protected Result result;
09     protected Result explicitResult;
10     protected String resultCode;
11     protected boolean executed = false;
12     protected boolean pushAction = true;
13     protected ObjectFactory objectFactory;
14     protected ActionEventListener actionEventListener;
15     protected ValueStackFactory valueStackFactory;
16     protected Container container;
17     private Configuration configuration;
18     protected UnknownHandlerManager unknownHandlerManager;

     核心方法是invoke()

1 interceptor.getInterceptor().intercept(DefaultActionInvocation.this);//调用拦截器
2 invokeActionOnly();//调用Action

    其中invokeActionOnly(Object action, ActionConfig actionConfig)调用Action中对应的方法为:

1 Method method = null;
2             try {
3                 method = getAction().getClass().getMethod(methodName, EMPTY_CLASS_ARRAY);
4             }
5   
6 if (!methodCalled) {
7                 methodResult = method.invoke(action, new Object[0]);//执行该方法
8             }

    创建Action: createAction(Map<String, Object> contextMap)

1 action = objectFactory.buildAction(proxy.getActionName(), proxy.getNamespace(), proxy.getConfig(), contextMap);
2 //...
3 if (actionEventListener != null) {
4             action = actionEventListener.prepare(action, stack);
5         }

  

2.5 ActionProxy:怎么找到Action:存放actionName 和ActionInvocation对象。在ActionInvocation对象的初始化时创建Action:init(ActionProxy proxy)  中调用createAction(contextMap); struts中默认的实现类是StrutsActionProxy

 2.6 ObjectFactory   

ObjectFactory is responsible for building the core framework objects. Users may register their own implementation of the ObjectFactory to control instantiation of these Objects.

This default implementation uses the buildBean method to create all classes (interceptors, actions, results, etc).

     buildBean(config.getClassName(), extraContext)这个方法做的事情很简单:用ClassLoader加载classname所对应的class,extraContext这个参数没有用到。

2.7 ConfigurationManager - central for XWork Configuration management, including its ConfigurationProvider.

2.8 ConfigurationProvider interface describes the framework's configuration. By default, the framework loads its configurations via an xml document by using the StrutsXmlConfigurationProvider.

3、简单步骤

客户端提起一个(HttpServletRequest)请求,如上文在浏览器中输入”http://localhost:8080/TestMvc/add.action”就是提起一个(HttpServletRequest)请求。

  1. 请求被提交到一系列(主要是三层)的过滤器(Filter),如(ActionContextCleanUp、其他过滤器(SiteMesh等)、 FilterDispatcher)。注意这里是有顺序的,先ActionContextCleanUp,再其他过滤器(SiteMesh等)、最后到FilterDispatcher。
  2. FilterDispatcher是控制器的核心,就是mvc中c控制层的核心。下面粗略的分析下我理解的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. public void serviceAction(HttpServletRequest request, HttpServletResponse response, String namespace, String actionName, Map requestMap, Map parameterMap, Map sessionMap, Map applicationMap) ...{ 
    48.         HashMap extraContext = createContextMap(requestMap, parameterMap, sessionMap, applicationMap, request, response, getServletConfig());  //实例化Map请求 ,询问ActionMapper是否需要调用某个Action来处理这个(request)请求
    49.         extraContext.put(SERVLET_DISPATCHER, this); 
    50.         OgnlValueStack stack = (OgnlValueStack) request.getAttribute(ServletActionContext.WEBWORK_VALUESTACK_KEY); 
    51.         if (stack != null) ...{ 
    52.             extraContext.put(ActionContext.VALUE_STACK,new OgnlValueStack(stack)); 
    53.         } 
    54.         try ...{ 
    55.             ActionProxy proxy = ActionProxyFactory.getFactory().createActionProxy(namespace, actionName, extraContext); 
    56. //这里actionName是通过两道getActionName解析出来的, FilterDispatcher把请求的处理交给ActionProxy,下面是ServletDispatcher的 TODO: 
    57.             request.setAttribute(ServletActionContext.WEBWORK_VALUESTACK_KEY, proxy.getInvocation().getStack()); 
    58.             proxy.execute(); 
    59.          //通过代理模式执行ActionProxy
    60.             if (stack != null)...{ 
    61.                 request.setAttribute(ServletActionContext.WEBWORK_VALUESTACK_KEY,stack); 
    62.             } 
    63.         } catch (ConfigurationException e) ...{ 
    64.             log.error("Could not find action", e); 
    65.             sendError(request, response, HttpServletResponse.SC_NOT_FOUND, e); 
    66.         } catch (Exception e) ...{ 
    67.             log.error("Could not execute action", e); 
    68.             sendError(request, response, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e); 
    69.         } 
    FilterDispatcher询问ActionMapper是否需要调用某个Action来处理这个(request)请求,如果ActionMapper决定需要调用某个Action,FilterDispatcher把请求的处理交给ActionProxy。
  3. ActionProxy通过Configuration Manager(struts.xml)询问框架的配置文件,找到需要调用的Action类.
    如上文的struts.xml配置
    1. <?xml version="1.0" encoding="GBK"?>
    2.  <!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN" "http://struts.apache.org/dtds/struts-2.0.dtd">
    3.  <struts>
    4.      <include file="struts-default.xml"/>
    5.      <package name="struts2" extends="struts-default">
    6.          <action name="add" 
    7.              class="edisundong.AddAction" >
    8.              <result>add.jsp</result>
    9.          </action>    
    10.      </package>
    11.  </struts>
    如果提交请求的是add.action,那么找到的Action类就是edisundong.AddAction。
  4. ActionProxy创建一个ActionInvocation的实例,同时ActionInvocation通过代理模式调用Action。但在调用之前ActionInvocation会根据配置加载Action相关的所有Interceptor。(Interceptor是struts2另一个核心级的概念)

    下面我们来看看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执行前后运行。
    那么什么是拦截器。
    拦截器就是AOP(Aspect-Oriented Programming)的一种实现。(AOP是指用于在某个方法或字段被访问之前,进行拦截然后在之前或之后加入某些操作。)
    拦截器的例子这里就不展开了。
    struts-default.xml文件摘取的内容:
    1. < interceptor name ="alias" class ="com.opensymphony.xwork2.interceptor.AliasInterceptor" /> 
    2. < interceptor name ="autowiring" class ="com.opensymphony.xwork2.spring.interceptor.ActionAutowiringInterceptor" /> 
    3. < interceptor name ="chain" class ="com.opensymphony.xwork2.interceptor.ChainingInterceptor" /> 
    4. < interceptor name ="conversionError" class ="org.apache.struts2.interceptor.StrutsConversionErrorInterceptor" /> 
    5. < interceptor name ="createSession" class ="org.apache.struts2.interceptor.CreateSessionInterceptor" /> 
    6. < interceptor name ="debugging" class ="org.apache.struts2.interceptor.debugging.DebuggingInterceptor" /> 
    7. < interceptor name ="external-ref" class ="com.opensymphony.xwork2.interceptor.ExternalReferencesInterceptor" /> 
    8. < interceptor name ="execAndWait" class ="org.apache.struts2.interceptor.ExecuteAndWaitInterceptor" /> 
    9. < interceptor name ="exception" class ="com.opensymphony.xwork2.interceptor.ExceptionMappingInterceptor" /> 
    10. < interceptor name ="fileUpload" class ="org.apache.struts2.interceptor.FileUploadInterceptor" /> 
    11. < interceptor name ="i18n" class ="com.opensymphony.xwork2.interceptor.I18nInterceptor" /> 
    12. < interceptor name ="logger" class ="com.opensymphony.xwork2.interceptor.LoggingInterceptor" /> 
    13. < interceptor name ="model-driven" class ="com.opensymphony.xwork2.interceptor.ModelDrivenInterceptor" /> 
    14. < interceptor name ="scoped-model-driven" class ="com.opensymphony.xwork2.interceptor.ScopedModelDrivenInterceptor" /> 
    15. < interceptor name ="params" class ="com.opensymphony.xwork2.interceptor.ParametersInterceptor" /> 
    16. < interceptor name ="prepare" class ="com.opensymphony.xwork2.interceptor.PrepareInterceptor" /> 
    17. < interceptor name ="static-params" class ="com.opensymphony.xwork2.interceptor.StaticParametersInterceptor" /> 
    18. < interceptor name ="scope" class ="org.apache.struts2.interceptor.ScopeInterceptor" /> 
    19. < interceptor name ="servlet-config" class ="org.apache.struts2.interceptor.ServletConfigInterceptor" /> 
    20. < interceptor name ="sessionAutowiring" class ="org.apache.struts2.spring.interceptor.SessionContextAutowiringInterceptor" /> 
    21. < interceptor name ="timer" class ="com.opensymphony.xwork2.interceptor.TimerInterceptor" /> 
    22. < interceptor name ="token" class ="org.apache.struts2.interceptor.TokenInterceptor" /> 
    23. < interceptor name ="token-session" class ="org.apache.struts2.interceptor.TokenSessionStoreInterceptor" /> 
    24. < interceptor name ="validation" class ="com.opensymphony.xwork2.validator.ValidationInterceptor" /> 
    25. < interceptor name ="workflow" class ="com.opensymphony.xwork2.interceptor.DefaultWorkflowInterceptor" /> 
    26. < interceptor name ="store" class ="org.apache.struts2.interceptor.MessageStoreInterceptor" /> 
    27. < interceptor name ="checkbox" class ="org.apache.struts2.interceptor.CheckboxInterceptor" /> 
    28. < interceptor name ="profiling" class ="org.apache.struts2.interceptor.ProfilingActivationInterceptor" /> 
    一旦Action执行完毕,ActionInvocation负责根据struts.xml中的配置找到对应的返回结果。如上文中将结构返回“add.jsp”,但大部分时候都是返回另外一个action,那么流程又得走一遍………

  总结:

  Struts2的工作流就只有这7步,比起Struts1简单了很多(本人能力有限,struts2更多的东西现在还看不明白)。网上有很多很多的关于.net和java的比较之类的文章,可是有几个作者是真正用过java和.net的呢?更多的评论都是人云亦云,想当然的评论java和.net。作为技术人千万不要屁股决定脑袋,关于web的设计模式上.net也不是那么一无是处,java也不是那么完美无缺

猜你喜欢

转载自feiyeguohai.iteye.com/blog/1186796
今日推荐