Struts2源码浅析-请求处理

StrutsPrepareAndExecuteFilter doFilter方法为请求的入口

doFilter方法主要做以下几件事

一: 根据配置的常量  设置当前request 字符编码  response国际化Locale信息

二: 创建ActionContext数据对象

三: 请求处理 

        1.分析url   根据url 创建ActionMapping对象   这些操作主要由ActionMapper接口实现类完成

        2. 执行请求逻辑动作

               ①.根据请求映射对象ActionMapping  创建ActionProxy 主要由ActionProxyFactory接口完成

               ②.执行Action 逻辑(拦截器,Action对应方法)

四:清理ActionContext数据对象

流程分析

  1. public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {  
  2.        HttpServletRequest request = (HttpServletRequest) req;  
  3.        HttpServletResponse response = (HttpServletResponse) res;  
  4.        try {  
  5.         //根据struts2常量配置   设置当前request Encoding 即request.setCharacterEncoding(encoding)   
  6.         //当前 response 设置国际化Locale信息 即response.setLocale(locale);   
  7.            prepare.setEncodingAndLocale(request, response);  
  8.            //创建ActionContext数据对象  包括ValueStack   
  9.            prepare.createActionContext(request, response);  
  10.            //将当前的Dispatcher保存到ThreadLocal中    
  11.            prepare.assignDispatcherToThread();  
  12.         if ( excludedPatterns != null && prepare.isUrlExcluded(request, excludedPatterns)) {  
  13.             chain.doFilter(request, response);  
  14.         } else {  
  15.             //包装request 返回StrutsRequestWrapper   
  16.             //StrutsRequestWrapper继承了HttpServletRequestWrapper   
  17.             request = prepare.wrapRequest(request);  
  18.             //创建ActionMapping   
  19.             ActionMapping mapping = prepare.findActionMapping(request, response, true);  
  20.             if (mapping == null) {  
  21.                 boolean handled = execute.executeStaticResourceRequest(request, response);  
  22.                 if (!handled) {  
  23.                     chain.doFilter(request, response);  
  24.                 }  
  25.             } else {  
  26.                 //真正执行Action的地方   
  27.                 execute.executeAction(request, response, mapping);  
  28.             }  
  29.         }  
  30.        } finally {  
  31.         //清除ActionContext    
  32.            prepare.cleanupRequest(request);  
  33.        }  
  34.    }  
 public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest) req;
        HttpServletResponse response = (HttpServletResponse) res;
        try {
        	//根据struts2常量配置   设置当前request Encoding 即request.setCharacterEncoding(encoding)
        	//当前 response 设置国际化Locale信息 即response.setLocale(locale);
            prepare.setEncodingAndLocale(request, response);
            //创建ActionContext数据对象  包括ValueStack
            prepare.createActionContext(request, response);
            //将当前的Dispatcher保存到ThreadLocal中 
            prepare.assignDispatcherToThread();
			if ( excludedPatterns != null && prepare.isUrlExcluded(request, excludedPatterns)) {
				chain.doFilter(request, response);
			} else {
				//包装request 返回StrutsRequestWrapper
				//StrutsRequestWrapper继承了HttpServletRequestWrapper
				request = prepare.wrapRequest(request);
				//创建ActionMapping
				ActionMapping mapping = prepare.findActionMapping(request, response, true);
				if (mapping == null) {
					boolean handled = execute.executeStaticResourceRequest(request, response);
					if (!handled) {
						chain.doFilter(request, response);
					}
				} else {
					//真正执行Action的地方
					execute.executeAction(request, response, mapping);
				}
			}
        } finally {
        	//清除ActionContext 
            prepare.cleanupRequest(request);
        }
    }

一:设置编码字符  国际化Locale信息,PrepareOperations#setEncodingAndLocale方法 调用了 Dispatcher#prepare方法  真正做事的还是Dispatcher

PrepareOperations类的setEncodingAndLocale 方法

  1. public void setEncodingAndLocale(HttpServletRequest request, HttpServletResponse response) {  
  2.     dispatcher.prepare(request, response);  
  3. }  
    public void setEncodingAndLocale(HttpServletRequest request, HttpServletResponse response) {
        dispatcher.prepare(request, response);
    }

Dispatcher的prepare方法

  1. public void prepare(HttpServletRequest request, HttpServletResponse response) {  
  2.     //struts.i18n.encoding 常量   
  3.     String encoding = null;  
  4.     if (defaultEncoding != null) {  
  5.         encoding = defaultEncoding;  
  6.     }  
  7.     Locale locale = null;  
  8.     if (defaultLocale != null) {  
  9.         locale = LocalizedTextUtil.localeFromString(defaultLocale, request.getLocale());  
  10.     }  
  11.     if (encoding != null) {  
  12.         try {  
  13.             request.setCharacterEncoding(encoding);  
  14.         } catch (Exception e) {  
  15.             LOG.error("Error setting character encoding to '" + encoding + "' - ignoring.", e);  
  16.         }  
  17.     }  
  18.     if (locale != null) {  
  19.         response.setLocale(locale);  
  20.     }  
  21. }  
    public void prepare(HttpServletRequest request, HttpServletResponse response) {
    	//struts.i18n.encoding 常量
        String encoding = null;
        if (defaultEncoding != null) {
            encoding = defaultEncoding;
        }
        Locale locale = null;
        if (defaultLocale != null) {
            locale = LocalizedTextUtil.localeFromString(defaultLocale, request.getLocale());
        }
        if (encoding != null) {
            try {
                request.setCharacterEncoding(encoding);
            } catch (Exception e) {
                LOG.error("Error setting character encoding to '" + encoding + "' - ignoring.", e);
            }
        }
        if (locale != null) {
            response.setLocale(locale);
        }
    }

二:创建ActionContext数据对象 由PrepareOperations#createActionContext方法完成

  1. public ActionContext createActionContext(HttpServletRequest request, HttpServletResponse response) {  
  2.     ActionContext ctx;  
  3.     Integer counter = 1;  
  4.     Integer oldCounter = (Integer) request.getAttribute(CLEANUP_RECURSION_COUNTER);  
  5.     if (oldCounter != null) {  
  6.         counter = oldCounter + 1;  
  7.     }  
  8.     //ActionContext与 ValueStack 是主从关系   
  9.     //ActionContext中持有ValueStack   
  10.     ActionContext oldContext = ActionContext.getContext();  
  11.     if (oldContext != null) {  
  12.         ctx = new ActionContext(new HashMap<String, Object>(oldContext.getContextMap()));  
  13.     } else {  
  14.         //ValueStack是由ValueStackFactory 创建   
  15.         ValueStack stack = dispatcher.getContainer().getInstance(ValueStackFactory.class).createValueStack();  
  16.         stack.getContext().putAll(dispatcher.createContextMap(request, response, null, servletContext));  
  17.         //将创建的ValueStack 保存到ActionContext   
  18.         ctx = new ActionContext(stack.getContext());  
  19.     }  
  20.     request.setAttribute(CLEANUP_RECURSION_COUNTER, counter);  
  21.     //将当前ActionContext 保存到ThreadLocal中   
  22.     ActionContext.setContext(ctx);  
  23.     return ctx;  
  24. }  
    public ActionContext createActionContext(HttpServletRequest request, HttpServletResponse response) {
        ActionContext ctx;
        Integer counter = 1;
        Integer oldCounter = (Integer) request.getAttribute(CLEANUP_RECURSION_COUNTER);
        if (oldCounter != null) {
            counter = oldCounter + 1;
        }
        //ActionContext与 ValueStack 是主从关系
        //ActionContext中持有ValueStack
        ActionContext oldContext = ActionContext.getContext();
        if (oldContext != null) {
            ctx = new ActionContext(new HashMap<String, Object>(oldContext.getContextMap()));
        } else {
        	//ValueStack是由ValueStackFactory 创建
            ValueStack stack = dispatcher.getContainer().getInstance(ValueStackFactory.class).createValueStack();
            stack.getContext().putAll(dispatcher.createContextMap(request, response, null, servletContext));
            //将创建的ValueStack 保存到ActionContext
            ctx = new ActionContext(stack.getContext());
        }
        request.setAttribute(CLEANUP_RECURSION_COUNTER, counter);
        //将当前ActionContext 保存到ThreadLocal中
        ActionContext.setContext(ctx);
        return ctx;
    }

三: 请求处理

1.创建ActionMapping对象  一个ActionMapping对象  对应一次请求,

ActionMapping定义

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

    private String name;
    private String namespace;
    private String method;
    private String extension;
    private Map<String, Object> params;
    private Result result;
}

PrepareOperations findActionMapping方法  创建ActionMaping对象的动作转交给ActionMapper接口的getMapping方法完成

  1. public ActionMapping findActionMapping(HttpServletRequest request, HttpServletResponse response, boolean forceLookup) {  
  2.     ActionMapping mapping = (ActionMapping) request.getAttribute(STRUTS_ACTION_MAPPING_KEY);  
  3.     if (mapping == null || forceLookup) {  
  4.         try {  
  5.             //ActionMapper 默认实现DefaultActionMapper   
  6.             //getMapping方法主要负责 查找对应的ActionConfig对象  根据ActionConfig对象创建 ActionMapping   
  7.             mapping = dispatcher.getContainer().getInstance(ActionMapper.class).getMapping(request, dispatcher.getConfigurationManager());  
  8.             if (mapping != null) {  
  9.                 request.setAttribute(STRUTS_ACTION_MAPPING_KEY, mapping);  
  10.             }  
  11.         } catch (Exception ex) {  
  12.             //错误信息   
  13.             dispatcher.sendError(request, response, servletContext, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, ex);  
  14.         }  
  15.     }  
  16.     return mapping;  
  17. }  
    public ActionMapping findActionMapping(HttpServletRequest request, HttpServletResponse response, boolean forceLookup) {
        ActionMapping mapping = (ActionMapping) request.getAttribute(STRUTS_ACTION_MAPPING_KEY);
        if (mapping == null || forceLookup) {
            try {
            	//ActionMapper 默认实现DefaultActionMapper
            	//getMapping方法主要负责 查找对应的ActionConfig对象  根据ActionConfig对象创建 ActionMapping
                mapping = dispatcher.getContainer().getInstance(ActionMapper.class).getMapping(request, dispatcher.getConfigurationManager());
                if (mapping != null) {
                    request.setAttribute(STRUTS_ACTION_MAPPING_KEY, mapping);
                }
            } catch (Exception ex) {
            	//错误信息
                dispatcher.sendError(request, response, servletContext, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, ex);
            }
        }
        return mapping;
    }

ActionMapper 的实现类 DefaultActionMapper , getMapping方法  分析url ,根据url查找到的ActionConfig对象 创建ActionMapping

  1. public ActionMapping getMapping(HttpServletRequest request,  
  2.                                 ConfigurationManager configManager) {  
  3.     //实例化ActionMapping   
  4.     ActionMapping mapping = new ActionMapping();  
  5.     String uri = getUri(request);  
  6.     int indexOfSemicolon = uri.indexOf(";");  
  7.     uri = (indexOfSemicolon > -1) ? uri.substring(0, indexOfSemicolon) : uri;  
  8.     uri = dropExtension(uri, mapping);  
  9.     if (uri == null) {  
  10.         return null;  
  11.     }  
  12.     // name, namspace处理   
  13.     parseNameAndNamespace(uri, mapping, configManager);  
  14.     handleSpecialParameters(request, mapping);  
  15.     if (mapping.getName() == null) {  
  16.         return null;  
  17.     }  
  18.     //处理action!menthod 形式   
  19.     parseActionName(mapping);  
  20.     return mapping;  
  21. }  
    public ActionMapping getMapping(HttpServletRequest request,
                                    ConfigurationManager configManager) {
    	//实例化ActionMapping
        ActionMapping mapping = new ActionMapping();
        String uri = getUri(request);
        int indexOfSemicolon = uri.indexOf(";");
        uri = (indexOfSemicolon > -1) ? uri.substring(0, indexOfSemicolon) : uri;
        uri = dropExtension(uri, mapping);
        if (uri == null) {
            return null;
        }
        // name, namspace处理
        parseNameAndNamespace(uri, mapping, configManager);
        handleSpecialParameters(request, mapping);
        if (mapping.getName() == null) {
            return null;
        }
        //处理action!menthod 形式
        parseActionName(mapping);
        return mapping;
    }
  1. protected void parseNameAndNamespace(String uri, ActionMapping mapping,  
  2.                                       ConfigurationManager configManager) {  
  3.      String namespace, name;  
  4.      int lastSlash = uri.lastIndexOf("/");  
  5.      if (lastSlash == -1) {  
  6.          namespace = "";  
  7.          name = uri;  
  8.      } else if (lastSlash == 0) {  
  9.          namespace = "/";  
  10.          name = uri.substring(lastSlash + 1);  
  11.      } else if (alwaysSelectFullNamespace) {  
  12.          // Simply select the namespace as everything before the last slash   
  13.          namespace = uri.substring(0, lastSlash);  
  14.          name = uri.substring(lastSlash + 1);  
  15.      } else {  
  16.         //配置元素管理器   
  17.          Configuration config = configManager.getConfiguration();  
  18.          String prefix = uri.substring(0, lastSlash);  
  19.          namespace = "";  
  20.          boolean rootAvailable = false;  
  21.          //config.getPackageConfigs()    
  22.          for (Object cfg : config.getPackageConfigs().values()) {  
  23.              String ns = ((PackageConfig) cfg).getNamespace();  
  24.              //匹配nameSpace    
  25.              if (ns != null && prefix.startsWith(ns) && (prefix.length() == ns.length() || prefix.charAt(ns.length()) == '/')) {  
  26.                  if (ns.length() > namespace.length()) {  
  27.                      namespace = ns;  
  28.                  }  
  29.              }  
  30.              if ("/".equals(ns)) {  
  31.                  rootAvailable = true;  
  32.              }  
  33.          }  
  34.          name = uri.substring(namespace.length() + 1);  
  35.          if (rootAvailable && "".equals(namespace)) {  
  36.              namespace = "/";  
  37.          }  
  38.      }  
  39.      if (!allowSlashesInActionNames && name != null) {  
  40.          int pos = name.lastIndexOf('/');  
  41.          if (pos > -1 && pos < name.length() - 1) {  
  42.              name = name.substring(pos + 1);  
  43.          }  
  44.      }  
  45.      //TODO   
  46.      mapping.setNamespace(namespace);  
  47.      mapping.setName(name);  
  48.  }  
   protected void parseNameAndNamespace(String uri, ActionMapping mapping,
                                         ConfigurationManager configManager) {
        String namespace, name;
        int lastSlash = uri.lastIndexOf("/");
        if (lastSlash == -1) {
            namespace = "";
            name = uri;
        } else if (lastSlash == 0) {
            namespace = "/";
            name = uri.substring(lastSlash + 1);
        } else if (alwaysSelectFullNamespace) {
            // Simply select the namespace as everything before the last slash
            namespace = uri.substring(0, lastSlash);
            name = uri.substring(lastSlash + 1);
        } else {
        	//配置元素管理器
            Configuration config = configManager.getConfiguration();
            String prefix = uri.substring(0, lastSlash);
            namespace = "";
            boolean rootAvailable = false;
            //config.getPackageConfigs() 
            for (Object cfg : config.getPackageConfigs().values()) {
                String ns = ((PackageConfig) cfg).getNamespace();
                //匹配nameSpace 
                if (ns != null && prefix.startsWith(ns) && (prefix.length() == ns.length() || prefix.charAt(ns.length()) == '/')) {
                    if (ns.length() > namespace.length()) {
                        namespace = ns;
                    }
                }
                if ("/".equals(ns)) {
                    rootAvailable = true;
                }
            }
            name = uri.substring(namespace.length() + 1);
            if (rootAvailable && "".equals(namespace)) {
                namespace = "/";
            }
        }
        if (!allowSlashesInActionNames && name != null) {
            int pos = name.lastIndexOf('/');
            if (pos > -1 && pos < name.length() - 1) {
                name = name.substring(pos + 1);
            }
        }
        //TODO
        mapping.setNamespace(namespace);
        mapping.setName(name);
    }

处理action!menthod 形式

  1. protected ActionMapping parseActionName(ActionMapping mapping) {  
  2.        if (mapping.getName() == null) {  
  3.            return mapping;  
  4.        }  
  5.        if (allowDynamicMethodCalls) {  
  6.            String name = mapping.getName();  
  7.            int exclamation = name.lastIndexOf("!");  
  8.            if (exclamation != -1) {  
  9.                mapping.setName(name.substring(0, exclamation));  
  10.                mapping.setMethod(name.substring(exclamation + 1));  
  11.            }  
  12.        }  
  13.        return mapping;  
  14.    }  
 protected ActionMapping parseActionName(ActionMapping mapping) {
        if (mapping.getName() == null) {
            return mapping;
        }
        if (allowDynamicMethodCalls) {
            String name = mapping.getName();
            int exclamation = name.lastIndexOf("!");
            if (exclamation != -1) {
                mapping.setName(name.substring(0, exclamation));
                mapping.setMethod(name.substring(exclamation + 1));
            }
        }
        return mapping;
    }

ActionMapping创建 时序图

 

 2.1根据请求映射对象ActionMapping 创建ActionProxy

回到StrutsPrepareAndExecuteFilter doFilter方法

  1. //执行Action 方法入口   
  2. execute.executeAction(request, response, mapping);  
//执行Action 方法入口
execute.executeAction(request, response, mapping);

ExecuteOperations 的 executeAction方法 把处理逻辑转交给了 Dispatcher的serviceAction方法

  1. public void executeAction(HttpServletRequest request, HttpServletResponse response, ActionMapping mapping) throws ServletException {  
  2.     dispatcher.serviceAction(request, response, servletContext, mapping);  
  3. }  
    public void executeAction(HttpServletRequest request, HttpServletResponse response, ActionMapping mapping) throws ServletException {
        dispatcher.serviceAction(request, response, servletContext, mapping);
    }

Dispatcher的serviceAction方法主要完成 1.创建ActionProxy,ActionInvocation,Action对象 2.执行对应的方法

ActionProxy是个接口  接口定义

  1. public interface ActionProxy {  
  2.   
  3.     /** 
  4.      * 我们定义的Action 
  5.      * ActionInvocation 中也持有Action引用 
  6.      * <br>------------------------------<br> 
  7.      * @return 
  8.      */  
  9.     Object getAction();  
  10.   
  11.     String getActionName();  
  12.   
  13.     /** 
  14.      * 初始化阶段 包装的对象 
  15.      * <br>------------------------------<br> 
  16.      * @return 
  17.      */  
  18.     ActionConfig getConfig();  
  19.   
  20.     /** 
  21.      * 该值决定 执行完Action对应的方法后 是否执行Result相关操作 
  22.      */  
  23.     void setExecuteResult(boolean executeResult);  
  24.   
  25.     /** 
  26.      * 
  27.      * @return the status 
  28.      */  
  29.     boolean getExecuteResult();  
  30.   
  31.     /** 
  32.      * 执行器 
  33.      */  
  34.     ActionInvocation getInvocation();  
  35.   
  36.     String getNamespace();  
  37.   
  38.     String execute() throws Exception;  
  39.       
  40.     /** 
  41.      * Action 对应的方法 
  42.      */  
  43.     String getMethod();  
  44. }  
public interface ActionProxy {

	/**
	 * 我们定义的Action
	 * ActionInvocation 中也持有Action引用
	 * <br>------------------------------<br>
	 * @return
	 */
    Object getAction();

    String getActionName();

    /**
     * 初始化阶段 包装的对象
     * <br>------------------------------<br>
     * @return
     */
    ActionConfig getConfig();

    /**
     * 该值决定 执行完Action对应的方法后 是否执行Result相关操作
     */
    void setExecuteResult(boolean executeResult);

    /**
     *
     * @return the status
     */
    boolean getExecuteResult();

    /**
     * 执行器
     */
    ActionInvocation getInvocation();

    String getNamespace();

    String execute() throws Exception;
    
    /**
     * Action 对应的方法
     */
    String getMethod();
}

ActionInvocation 负责执行所有的拦截器Interceptor和我们定义的Action方法

ActionInvocation接口定义 

  1. /** 
  2.  * Action 执行器 
  3.  */  
  4. public interface ActionInvocation extends Serializable {  
  5.   
  6.     /** 
  7.      * 我们定义的Action 
  8.      * <br>------------------------------<br> 
  9.      * @return 
  10.      */  
  11.     Object getAction();  
  12.   
  13.     boolean isExecuted();  
  14.   
  15.     ActionContext getInvocationContext();  
  16.   
  17.     ActionProxy getProxy();  
  18.   
  19.     Result getResult() throws Exception;  
  20.   
  21.     /** 
  22.      * Action 对应方法执行完成后  返回的Result   
  23.      * <br>------------------------------<br> 
  24.      * @return 
  25.      */  
  26.     String getResultCode();  
  27.   
  28.     void setResultCode(String resultCode);  
  29.   
  30.     ValueStack getStack();  
  31.   
  32.     void addPreResultListener(PreResultListener listener);  
  33.       
  34.     /** 
  35.      * 执行所有操作 
  36.      * 1.执行拦截器 
  37.      * 2.调用invokeActionOnly方法执行 action对应方法 
  38.      * <br>------------------------------<br> 
  39.      * @return 
  40.      * @throws Exception 
  41.      */  
  42.     String invoke() throws Exception;  
  43.   
  44.     /** 
  45.      * 执行我们定义的Action 方法  在invoke方法中调用 
  46.      * <br>------------------------------<br> 
  47.      * @return 
  48.      * @throws Exception 
  49.      */  
  50.     String invokeActionOnly() throws Exception;  
  51.   
  52.     void setActionEventListener(ActionEventListener listener);  
  53.   
  54.     /** 
  55.      *  这个方法会创建我们定义的Action 
  56.      * <br>------------------------------<br> 
  57.      * @param proxy 
  58.      */  
  59.     void init(ActionProxy proxy) ;  
  60. }  
/**
 * Action 执行器
 */
public interface ActionInvocation extends Serializable {

	/**
	 * 我们定义的Action
	 * <br>------------------------------<br>
	 * @return
	 */
    Object getAction();

    boolean isExecuted();

    ActionContext getInvocationContext();

    ActionProxy getProxy();

    Result getResult() throws Exception;

    /**
     * Action 对应方法执行完成后  返回的Result  
     * <br>------------------------------<br>
     * @return
     */
    String getResultCode();

    void setResultCode(String resultCode);

    ValueStack getStack();

    void addPreResultListener(PreResultListener listener);
    
    /**
     * 执行所有操作
     * 1.执行拦截器
     * 2.调用invokeActionOnly方法执行 action对应方法
     * <br>------------------------------<br>
     * @return
     * @throws Exception
     */
    String invoke() throws Exception;

    /**
     * 执行我们定义的Action 方法  在invoke方法中调用
     * <br>------------------------------<br>
     * @return
     * @throws Exception
     */
    String invokeActionOnly() throws Exception;

    void setActionEventListener(ActionEventListener listener);

    /**
     *  这个方法会创建我们定义的Action
     * <br>------------------------------<br>
     * @param proxy
     */
    void init(ActionProxy proxy) ;
}

Dispatcher的serviceAction方法

  1. public void serviceAction(HttpServletRequest request, HttpServletResponse response, ServletContext context, ActionMapping mapping) throws ServletException {  
  2.     //1.保存request, session, 等web元素到map中   
  3.     Map<String, Object> extraContext = createContextMap(request, response, mapping, context);  
  4.     // 省略   
  5.     //TODO   
  6.     String namespace = mapping.getNamespace();  
  7.     String name = mapping.getName();  
  8.     String method = mapping.getMethod();  
  9.     //2.初始化完成之后  解析的xml数据对象 会保存到 Configuration#runtimeConfiguration变量中   
  10.     Configuration config = configurationManager.getConfiguration();  
  11.     //3.创建ActionProxy,ActionInvocation 返回StrutsActionProxy   
  12.     ActionProxy proxy = config.getContainer().getInstance(ActionProxyFactory.class).createActionProxy(namespace, name, method, extraContext, truefalse);  
  13.     request.setAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY, proxy.getInvocation().getStack());  
  14.     //执行Action 对应方法入口   
  15.     if (mapping.getResult() != null) {  
  16.         Result result = mapping.getResult();  
  17.         result.execute(proxy.getInvocation());  
  18.     } else {  
  19.     //StrutsActionProxy#execute()方法   
  20.     //4.实际是转到了ActionInvocation#invoke方法   
  21.         proxy.execute();  
  22.     }  
  23. }  
	public void serviceAction(HttpServletRequest request, HttpServletResponse response, ServletContext context, ActionMapping mapping) throws ServletException {
		//1.保存request, session, 等web元素到map中
		Map<String, Object> extraContext = createContextMap(request, response, mapping, context);
		// 省略
		//TODO
		String namespace = mapping.getNamespace();
		String name = mapping.getName();
		String method = mapping.getMethod();
		//2.初始化完成之后  解析的xml数据对象 会保存到 Configuration#runtimeConfiguration变量中
		Configuration config = configurationManager.getConfiguration();
		//3.创建ActionProxy,ActionInvocation 返回StrutsActionProxy
		ActionProxy proxy = config.getContainer().getInstance(ActionProxyFactory.class).createActionProxy(namespace, name, method, extraContext, true, false);
		request.setAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY, proxy.getInvocation().getStack());
		//执行Action 对应方法入口
		if (mapping.getResult() != null) {
			Result result = mapping.getResult();
			result.execute(proxy.getInvocation());
		} else {
		//StrutsActionProxy#execute()方法
		//4.实际是转到了ActionInvocation#invoke方法
			proxy.execute();
		}
	}

createContextMap 方法 保存web元素 最终已map的形式返回

  1. public Map<String, Object> createContextMap(HttpServletRequest request, HttpServletResponse response, ActionMapping mapping, ServletContext context) {  
  2.     Map requestMap = new RequestMap(request);  
  3.     Map params = new HashMap(request.getParameterMap());  
  4.     Map session = new SessionMap(request);  
  5.     Map application = new ApplicationMap(context);  
  6.     //包装成map集合   
  7.     Map<String, Object> extraContext = createContextMap(requestMap, params, session, application, request, response, context);  
  8.     if (mapping != null) {  
  9.         extraContext.put(ServletActionContext.ACTION_MAPPING, mapping);  
  10.     }  
  11.     return extraContext;  
  12. }  
	public Map<String, Object> createContextMap(HttpServletRequest request, HttpServletResponse response, ActionMapping mapping, ServletContext context) {
		Map requestMap = new RequestMap(request);
		Map params = new HashMap(request.getParameterMap());
		Map session = new SessionMap(request);
		Map application = new ApplicationMap(context);
		//包装成map集合
		Map<String, Object> extraContext = createContextMap(requestMap, params, session, application, request, response, context);
		if (mapping != null) {
			extraContext.put(ServletActionContext.ACTION_MAPPING, mapping);
		}
		return extraContext;
	}
  1. public HashMap<String, Object> createContextMap(Map requestMap, Map parameterMap, Map sessionMap, Map applicationMap, HttpServletRequest request, HttpServletResponse response, ServletContext servletContext) {  
  2.         HashMap<String, Object> extraContext = new HashMap<String, Object>();  
  3.         extraContext.put(ActionContext.PARAMETERS, new HashMap(parameterMap));  
  4.         extraContext.put(ActionContext.SESSION, sessionMap);  
  5.         extraContext.put(ActionContext.APPLICATION, applicationMap);  
  6.         Locale locale;  
  7.         if (defaultLocale != null) {  
  8.             locale = LocalizedTextUtil.localeFromString(defaultLocale, request.getLocale());  
  9.         } else {  
  10.             locale = request.getLocale();  
  11.         }  
  12.   
  13.         extraContext.put(ActionContext.LOCALE, locale);  
  14.         //extraContext.put(ActionContext.DEV_MODE, Boolean.valueOf(devMode));   
  15.   
  16.         // value为HttpServletRequest   
  17.         //HttpServletRequest = extraContext.get('StrutsStatics.HTTP_REQUEST')   
  18.         extraContext.put(StrutsStatics.HTTP_REQUEST, request);  
  19.         extraContext.put(StrutsStatics.HTTP_RESPONSE, response);  
  20.         extraContext.put(StrutsStatics.SERVLET_CONTEXT, servletContext);  
  21.         //value为包装过的 元素map    
  22.         //获取方式extraContext.get('request').requestMap.get('key')   
  23.         extraContext.put("request", requestMap);  
  24.         extraContext.put("session", sessionMap);  
  25.         extraContext.put("application", applicationMap);  
  26.         extraContext.put("parameters", parameterMap);  
  27.   
  28.         AttributeMap attrMap = new AttributeMap(extraContext);  
  29.         extraContext.put("attr", attrMap);  
  30.   
  31.         return extraContext;  
  32.     }  
public HashMap<String, Object> createContextMap(Map requestMap, Map parameterMap, Map sessionMap, Map applicationMap, HttpServletRequest request, HttpServletResponse response, ServletContext servletContext) {
		HashMap<String, Object> extraContext = new HashMap<String, Object>();
		extraContext.put(ActionContext.PARAMETERS, new HashMap(parameterMap));
		extraContext.put(ActionContext.SESSION, sessionMap);
		extraContext.put(ActionContext.APPLICATION, applicationMap);
		Locale locale;
		if (defaultLocale != null) {
			locale = LocalizedTextUtil.localeFromString(defaultLocale, request.getLocale());
		} else {
			locale = request.getLocale();
		}

		extraContext.put(ActionContext.LOCALE, locale);
		//extraContext.put(ActionContext.DEV_MODE, Boolean.valueOf(devMode));

		// value为HttpServletRequest
		//HttpServletRequest = extraContext.get('StrutsStatics.HTTP_REQUEST')
		extraContext.put(StrutsStatics.HTTP_REQUEST, request);
		extraContext.put(StrutsStatics.HTTP_RESPONSE, response);
		extraContext.put(StrutsStatics.SERVLET_CONTEXT, servletContext);
		//value为包装过的 元素map 
		//获取方式extraContext.get('request').requestMap.get('key')
		extraContext.put("request", requestMap);
		extraContext.put("session", sessionMap);
		extraContext.put("application", applicationMap);
		extraContext.put("parameters", parameterMap);

		AttributeMap attrMap = new AttributeMap(extraContext);
		extraContext.put("attr", attrMap);

		return extraContext;
	}

创建ActionProxy,ActionInvocation 是由ActionProxyFactory实现类完成

DefaultActionProxyFactory createActionProxy方法

  1. public ActionProxy createActionProxy(String namespace, String actionName, String methodName, Map<String, Object> extraContext, boolean executeResult, boolean cleanupContext) {  
  2.     //创建ActionInvocation   
  3.      ActionInvocation inv = new DefaultActionInvocation(extraContext, true);  
  4.      //对该ActionInvocation 实例 进行依赖注入 即引用了@Inject注解的 方法 变量..   
  5.      container.inject(inv);  
  6.      //创建ActionProxy     
  7.      //ActionProxy,ActionInvocation都互相持有对方的引用   
  8.      //子类StrutsActionProxyFactory 重写了该方法   
  9.      return createActionProxy(inv, namespace, actionName, methodName, executeResult, cleanupContext);  
  10.  }  
   public ActionProxy createActionProxy(String namespace, String actionName, String methodName, Map<String, Object> extraContext, boolean executeResult, boolean cleanupContext) {
    	//创建ActionInvocation
        ActionInvocation inv = new DefaultActionInvocation(extraContext, true);
        //对该ActionInvocation 实例 进行依赖注入 即引用了@Inject注解的 方法 变量..
        container.inject(inv);
        //创建ActionProxy  
        //ActionProxy,ActionInvocation都互相持有对方的引用
        //子类StrutsActionProxyFactory 重写了该方法
        return createActionProxy(inv, namespace, actionName, methodName, executeResult, cleanupContext);
    }

StrutsActionProxyFactory 的createActionProxy方法,   StrutsActionProxyFactory是DefaultActionProxyFactory的子类

  1. public ActionProxy createActionProxy(ActionInvocation inv, String namespace, String actionName, String methodName, boolean executeResult, boolean cleanupContext) {  
  2.     StrutsActionProxy proxy = new StrutsActionProxy(inv, namespace, actionName, methodName, executeResult, cleanupContext);  
  3.     container.inject(proxy);  
  4.     //这里会创建action   
  5.     proxy.prepare();  
  6.     return proxy;  
  7. }  
    public ActionProxy createActionProxy(ActionInvocation inv, String namespace, String actionName, String methodName, boolean executeResult, boolean cleanupContext) {
        StrutsActionProxy proxy = new StrutsActionProxy(inv, namespace, actionName, methodName, executeResult, cleanupContext);
        container.inject(proxy);
        //这里会创建action
        proxy.prepare();
        return proxy;
    }

StrutsActionProxyFactory 的prepare方法  主要完成调用ActionInvocation  init方法 创建我们定义的Action  也可能是从Spring容器获得

  1. protected void prepare()  {  
  2.  //从configuration runtimeConfiguration对象中获取ActionConfig   
  3.  config = configuration.getRuntimeConfiguration().getActionConfig(namespace, actionName);  
  4.  //...略   
  5.  //ActionConfig method为空 默认设置为"execute"     
  6.  resolveMethod();  
  7.  //检查method 在Action是否存在   
  8.  if (!config.isAllowedMethod(method)) {  
  9.      throw new ConfigurationException("Invalid method: "+method+" for action "+actionName);  
  10.  }  
  11.  //创建Action 可能是从spring容器中获得   
  12.  invocation.init(this);  
  13. }  
    protected void prepare()  {
	    //从configuration runtimeConfiguration对象中获取ActionConfig
	    config = configuration.getRuntimeConfiguration().getActionConfig(namespace, actionName);
	    //...略
	    //ActionConfig method为空 默认设置为"execute"  
	    resolveMethod();
	    //检查method 在Action是否存在
	    if (!config.isAllowedMethod(method)) {
	        throw new ConfigurationException("Invalid method: "+method+" for action "+actionName);
	    }
	    //创建Action 可能是从spring容器中获得
	    invocation.init(this);
    }

DefaultActionInvocation  init方法  

  1. public void init(ActionProxy proxy) {  
  2.     this.proxy = proxy;  
  3.     Map<String, Object> contextMap = createContextMap();  
  4.     ActionContext actionContext = ActionContext.getContext();  
  5.     if (actionContext != null) {  
  6.         actionContext.setActionInvocation(this);  
  7.     }  
  8.     // 创建Action   
  9.     createAction(contextMap);  
  10.     if (pushAction) {  
  11.         stack.push(action);  
  12.         contextMap.put("action", action);  
  13.     }  
  14.     invocationContext = new ActionContext(contextMap);  
  15.     invocationContext.setName(proxy.getActionName());  
  16.     //从当前mapping对应的ActionConfig获得拦截器   
  17.     List<InterceptorMapping> interceptorList = new ArrayList<InterceptorMapping>(proxy.getConfig().getInterceptors());  
  18.     interceptors = interceptorList.iterator();  
  19. }  
    public void init(ActionProxy proxy) {
        this.proxy = proxy;
        Map<String, Object> contextMap = createContextMap();
        ActionContext actionContext = ActionContext.getContext();
        if (actionContext != null) {
            actionContext.setActionInvocation(this);
        }
        // 创建Action
        createAction(contextMap);
        if (pushAction) {
            stack.push(action);
            contextMap.put("action", action);
        }
        invocationContext = new ActionContext(contextMap);
        invocationContext.setName(proxy.getActionName());
        //从当前mapping对应的ActionConfig获得拦截器
        List<InterceptorMapping> interceptorList = new ArrayList<InterceptorMapping>(proxy.getConfig().getInterceptors());
        interceptors = interceptorList.iterator();
    }
  1. protected void createAction(Map<String, Object> contextMap) {  
  2.     //省略...   
  3.     // load action   
  4.      //Action的创建在此发生   
  5.     action = objectFactory.buildAction(proxy.getActionName(), proxy.getNamespace(), proxy.getConfig(), contextMap);  
  6.     //省略...   
  7.     if (actionEventListener != null) {  
  8.         action = actionEventListener.prepare(action, stack);  
  9.     }  
  10. }  
    protected void createAction(Map<String, Object> contextMap) {
    	//省略...
        // load action
         //Action的创建在此发生
        action = objectFactory.buildAction(proxy.getActionName(), proxy.getNamespace(), proxy.getConfig(), contextMap);
        //省略...
        if (actionEventListener != null) {
            action = actionEventListener.prepare(action, stack);
        }
    }

ObjectFactory 主要负责bean 的创建  继承关系:

以spring为例 StrutsSpringObjectFactory

ObjectFactory bulidAction方法 转到bulidBean方法

  1. public Object buildAction(String actionName, String namespace, ActionConfig config, Map<String, Object> extraContext) throws Exception {  
  2.     return buildBean(config.getClassName(), extraContext);  
  3. }  
    public Object buildAction(String actionName, String namespace, ActionConfig config, Map<String, Object> extraContext) throws Exception {
        return buildBean(config.getClassName(), extraContext);
    }

SpringObjectFactory 重写了ObjectFactory 的buildBean方法 

主要从spring容器中获得bean 这里使用的是spring 的AutowireCapableBeanFactory容器 具有自动装配特性

  1. public Object buildBean(Class clazz, Map<String, Object> extraContext) throws Exception {  
  2.     Object bean;  
  3.   
  4.     try {  
  5.         // Decide to follow autowire strategy or use the legacy approach which mixes injection strategies   
  6.         if (alwaysRespectAutowireStrategy) {  
  7.             // Leave the creation up to Spring   
  8.             bean = autoWiringFactory.createBean(clazz, autowireStrategy, false);  
  9.             injectApplicationContext(bean);  
  10.             return injectInternalBeans(bean);  
  11.         } else {  
  12.             bean = autoWiringFactory.autowire(clazz, AutowireCapableBeanFactory.AUTOWIRE_CONSTRUCTOR, false);  
  13.             bean = autoWiringFactory.applyBeanPostProcessorsBeforeInitialization(bean, bean.getClass().getName());  
  14.             // We don't need to call the init-method since one won't be registered.   
  15.             bean = autoWiringFactory.applyBeanPostProcessorsAfterInitialization(bean, bean.getClass().getName());  
  16.             return autoWireBean(bean, autoWiringFactory);  
  17.         }  
  18.     } catch (UnsatisfiedDependencyException e) {  
  19.         if (LOG.isErrorEnabled())  
  20.             LOG.error("Error building bean", e);  
  21.         // Fall back   
  22.         return autoWireBean(super.buildBean(clazz, extraContext), autoWiringFactory);  
  23.     }  
  24. }  
    public Object buildBean(Class clazz, Map<String, Object> extraContext) throws Exception {
        Object bean;

        try {
            // Decide to follow autowire strategy or use the legacy approach which mixes injection strategies
            if (alwaysRespectAutowireStrategy) {
                // Leave the creation up to Spring
                bean = autoWiringFactory.createBean(clazz, autowireStrategy, false);
                injectApplicationContext(bean);
                return injectInternalBeans(bean);
            } else {
                bean = autoWiringFactory.autowire(clazz, AutowireCapableBeanFactory.AUTOWIRE_CONSTRUCTOR, false);
                bean = autoWiringFactory.applyBeanPostProcessorsBeforeInitialization(bean, bean.getClass().getName());
                // We don't need to call the init-method since one won't be registered.
                bean = autoWiringFactory.applyBeanPostProcessorsAfterInitialization(bean, bean.getClass().getName());
                return autoWireBean(bean, autoWiringFactory);
            }
        } catch (UnsatisfiedDependencyException e) {
            if (LOG.isErrorEnabled())
                LOG.error("Error building bean", e);
            // Fall back
            return autoWireBean(super.buildBean(clazz, extraContext), autoWiringFactory);
        }
    }

ActionProxy, ActionInvocation创建过程结束了 

当前的ActionInvocation对象中 持有当前映射匹配的拦截器集合interceptors,ActionProxy和我们定义的action对象

目前还没有执行Action对应方法  万事俱备只欠东风了。

ActionProxy创建时序图

2.2 执行Action逻辑   真正执行逻辑是在ActionInvocation的invoke方法中发生

回到Dispatcher 的serviceAction方法

  1. //StrutsActionProxy#execute()方法   
  2. //实际是转到了ActionInvocation#invoke方法   
  3. proxy.execute();  
//StrutsActionProxy#execute()方法
//实际是转到了ActionInvocation#invoke方法
proxy.execute();

StrutsActionProxy的 execute方法调用ActionInvocation invoke方法

  1. public String execute() throws Exception {  
  2.     ActionContext previous = ActionContext.getContext();  
  3.     ActionContext.setContext(invocation.getInvocationContext());  
  4.     try {  
  5.         return invocation.invoke();  
  6.     } finally {  
  7.         if (cleanupContext)  
  8.             ActionContext.setContext(previous);  
  9.     }  
  10. }  
    public String execute() throws Exception {
        ActionContext previous = ActionContext.getContext();
        ActionContext.setContext(invocation.getInvocationContext());
        try {
            return invocation.invoke();
        } finally {
            if (cleanupContext)
                ActionContext.setContext(previous);
        }
    }

ActionInvocation invoke方法

大致执行步骤1.执行所有的拦截器 2.执行Action对应的Method 3.根据Action执行结果 再执行Result

  1. public String invoke() throws Exception {  
  2.     //...省略   
  3.     //1.先执行所有拦截器   
  4.     if (interceptors.hasNext()) {  
  5.         //这里类似一个递归调用   
  6.         //intercept方法中 invocation.invoke();   
  7.        final InterceptorMapping interceptor = (InterceptorMapping) interceptors.next();  
  8.        resultCode = interceptor.getInterceptor().intercept(DefaultActionInvocation.this);  
  9.     } else {  
  10.         //2.最后 执行Action对应方法  返回result字符串   
  11.         resultCode = invokeActionOnly();  
  12.     }  
  13.     //...省略   
  14.     if (proxy.getExecuteResult()) {  
  15.         //3.实例化Result对象   
  16.         executeResult();  
  17.     }  
  18.     return resultCode;  
  19. }  
    public String invoke() throws Exception {
    	//...省略
        //1.先执行所有拦截器
        if (interceptors.hasNext()) {
        	//这里类似一个递归调用
        	//intercept方法中 invocation.invoke();
           final InterceptorMapping interceptor = (InterceptorMapping) interceptors.next();
           resultCode = interceptor.getInterceptor().intercept(DefaultActionInvocation.this);
        } else {
        	//2.最后 执行Action对应方法  返回result字符串
            resultCode = invokeActionOnly();
        }
    	//...省略
        if (proxy.getExecuteResult()) {
        	//3.实例化Result对象
            executeResult();
        }
        return resultCode;
    }

拦截器的执行  interceptors为一个迭代器Iterator  当执行完一个拦截器   拦截器中又会回调 invoke方法执行下一个  例如:

  1. public String intercept(ActionInvocation invocation) throws Exception {  
  2.     String result = null;  
  3.     //回调到DefaultActionInvocation#invoke方法   
  4.     result = invocation.invoke();  
  5.     return result;  
  6. }  
    public String intercept(ActionInvocation invocation) throws Exception {
        String result = null;
        //回调到DefaultActionInvocation#invoke方法
        result = invocation.invoke();
        return result;
    }

拦截器执行完成 接着执行Action 对应方法  在invokeActionOnly发生

  1. public String invokeActionOnly() throws Exception {  
  2.     return invokeAction(getAction(), proxy.getConfig());  
  3. }  
    public String invokeActionOnly() throws Exception {
        return invokeAction(getAction(), proxy.getConfig());
    }
  1. protected String invokeAction(Object action, ActionConfig actionConfig) throws Exception {  
  2.     //要执行的方法   
  3.     String methodName = proxy.getMethod();  
  4.   
  5.     try {  
  6.         Object methodResult = null;  
  7.         Method method = null;  
  8.         //获得Method对象   
  9.         method = getAction().getClass().getMethod(methodName, EMPTY_CLASS_ARRAY);  
  10.         //执行Action 方法   
  11.         methodResult = method.invoke(action, new Object[0]);  
  12.         if (methodResult instanceof Result) {  
  13.             this.explicitResult = (Result) methodResult;  
  14.             container.inject(explicitResult);  
  15.             return null;  
  16.         } else {  
  17.             //返回 result Str   
  18.             return (String) methodResult;  
  19.         }  
  20.     } catch (NoSuchMethodException e) {  
  21.         throw new IllegalArgumentException("The " + methodName + "() is not defined in action " + getAction().getClass() + "");  
  22.     } catch (InvocationTargetException e) {  
  23.         Throwable t = e.getTargetException();  
  24.         if (actionEventListener != null) {  
  25.             //异常处理   
  26.             String result = actionEventListener.handleException(t, getStack());  
  27.             if (result != null) {  
  28.                 return result;  
  29.             }  
  30.         }  
  31.     }   
  32. }  
    protected String invokeAction(Object action, ActionConfig actionConfig) throws Exception {
    	//要执行的方法
        String methodName = proxy.getMethod();

        try {
            Object methodResult = null;
            Method method = null;
            //获得Method对象
        	method = getAction().getClass().getMethod(methodName, EMPTY_CLASS_ARRAY);
        	//执行Action 方法
        	methodResult = method.invoke(action, new Object[0]);
            if (methodResult instanceof Result) {
                this.explicitResult = (Result) methodResult;
                container.inject(explicitResult);
                return null;
            } else {
            	//返回 result Str
                return (String) methodResult;
            }
        } catch (NoSuchMethodException e) {
            throw new IllegalArgumentException("The " + methodName + "() is not defined in action " + getAction().getClass() + "");
        } catch (InvocationTargetException e) {
            Throwable t = e.getTargetException();
            if (actionEventListener != null) {
            	//异常处理
                String result = actionEventListener.handleException(t, getStack());
                if (result != null) {
                    return result;
                }
            }
        } 
    }

执行Result 根据ResultConfig 中的calssName创建result对象  在执行execute

  1. private void executeResult() throws Exception {  
  2.     //根据ResultConfig对象创建Result对象   
  3.     result = createResult();  
  4.     result.execute(this);  
  5. }  
    private void executeResult() throws Exception {
    	//根据ResultConfig对象创建Result对象
        result = createResult();
        result.execute(this);
    }
  1. public Result createResult() throws Exception {  
  2.        if (explicitResult != null) {  
  3.            Result ret = explicitResult;  
  4.            explicitResult = null;  
  5.   
  6.            return ret;  
  7.        }  
  8.        ActionConfig config = proxy.getConfig();  
  9.        Map<String, ResultConfig> results = config.getResults();  
  10.        ResultConfig resultConfig = null;  
  11.        try {  
  12.            resultConfig = results.get(resultCode);  
  13.        } catch (NullPointerException e) {  
  14.            // swallow   
  15.        }  
  16.        if (resultConfig == null) {  
  17.            // If no result is found for the given resultCode, try to get a wildcard '*' match.   
  18.            resultConfig = results.get("*");  
  19.        }  
  20.        if (resultConfig != null) {  
  21.            try {  
  22.             //创建Result对象   
  23.             //resultConfig中包含了 className 直   
  24.                return objectFactory.buildResult(resultConfig, invocationContext.getContextMap());  
  25.            } catch (Exception e) {  
  26.                LOG.error("There was an exception while instantiating the result of type " + resultConfig.getClassName(), e);  
  27.                throw new XWorkException(e, resultConfig);  
  28.            }  
  29.        } else if (resultCode != null && !Action.NONE.equals(resultCode) && unknownHandlerManager.hasUnknownHandlers()) {  
  30.            return unknownHandlerManager.handleUnknownResult(invocationContext, proxy.getActionName(), proxy.getConfig(), resultCode);  
  31.        }  
  32.        return null;  
  33.    }  
 public Result createResult() throws Exception {
        if (explicitResult != null) {
            Result ret = explicitResult;
            explicitResult = null;

            return ret;
        }
        ActionConfig config = proxy.getConfig();
        Map<String, ResultConfig> results = config.getResults();
        ResultConfig resultConfig = null;
        try {
            resultConfig = results.get(resultCode);
        } catch (NullPointerException e) {
            // swallow
        }
        if (resultConfig == null) {
            // If no result is found for the given resultCode, try to get a wildcard '*' match.
            resultConfig = results.get("*");
        }
        if (resultConfig != null) {
            try {
            	//创建Result对象
            	//resultConfig中包含了 className 直
                return objectFactory.buildResult(resultConfig, invocationContext.getContextMap());
            } catch (Exception e) {
                LOG.error("There was an exception while instantiating the result of type " + resultConfig.getClassName(), e);
                throw new XWorkException(e, resultConfig);
            }
        } else if (resultCode != null && !Action.NONE.equals(resultCode) && unknownHandlerManager.hasUnknownHandlers()) {
            return unknownHandlerManager.handleUnknownResult(invocationContext, proxy.getActionName(), proxy.getConfig(), resultCode);
        }
        return null;
    }

执行Result execute方法  以ServletDispatcherResult为例

  1. public void execute(ActionInvocation invocation) throws Exception {  
  2.     lastFinalLocation = conditionalParse(location, invocation);  
  3.     doExecute(lastFinalLocation, invocation);  
  4. }  
    public void execute(ActionInvocation invocation) throws Exception {
        lastFinalLocation = conditionalParse(location, invocation);
        doExecute(lastFinalLocation, invocation);
    }
  1. public void doExecute(String finalLocation, ActionInvocation invocation) throws Exception {  
  2.     PageContext pageContext = ServletActionContext.getPageContext();  
  3.     if (pageContext != null) {  
  4.         pageContext.include(finalLocation);  
  5.     } else {  
  6.         //...省略   
  7.         if (!insideActionTag && !response.isCommitted() && (request.getAttribute("javax.servlet.include.servlet_path") == null)) {  
  8.             request.setAttribute("struts.view_uri", finalLocation);  
  9.             request.setAttribute("struts.request_uri", request.getRequestURI());  
  10.             //转向   
  11.             dispatcher.forward(request, response);  
  12.         } else {  
  13.             dispatcher.include(request, response);  
  14.         }  
  15.     }  
  16. }  
    public void doExecute(String finalLocation, ActionInvocation invocation) throws Exception {
        PageContext pageContext = ServletActionContext.getPageContext();
        if (pageContext != null) {
            pageContext.include(finalLocation);
        } else {
            //...省略
            if (!insideActionTag && !response.isCommitted() && (request.getAttribute("javax.servlet.include.servlet_path") == null)) {
                request.setAttribute("struts.view_uri", finalLocation);
                request.setAttribute("struts.request_uri", request.getRequestURI());
                //转向
                dispatcher.forward(request, response);
            } else {
                dispatcher.include(request, response);
            }
        }
    }

请求时序图:


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值