1.启动web应用程序
在web.xml中配置了StrutsPrepareAndExecuteFilter拦截器,因此web应用程序启动时,服务器将创建StrutsPrepareAndExecuteFilter实例对象,并调用对象的init()完成初始化,init()方法在Filter的整个生命周期之后只会被执行一次
在init()方法中,根据配置信息初始化PrepareOperations 和ExecuteOperations对象
2.客户端发送请求
在web.xml中配置的StrutsPrepareAndExecuteFilter拦截所有请求,因此,请求被拦截,调用doFilter方法
在doFilter方法中,创建ActionContext对象,并将ActionContext对象放入ThreadLocal中
判断当前请求是否为不需要拦截的请求,是,直接调用chain.doFilter方法放行
否则,获取ActionMapping对象,判断该对象是否为nul
如果是null,放行
否则,调用ExecuteOperations的executeAction方法,在该方法中调用Dispatcher的serviceAction方法
ActionMapping对象,就是struts.xml中的配置
3.Dispatcher的serviceAction方法 public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException
HttpServletRequest request = (HttpServletRequest) req; HttpServletResponse response = (HttpServletResponse) res; try { prepare.setEncodingAndLocale(request, response); //设置字符编码和国际化资源 prepare.createActionContext(request, response); //创建ActionContext对象 prepare.assignDispatcherToThread(); if ( excludedPatterns != null && prepare.isUrlExcluded(request, excludedPatterns)) { // 判断当前请求是否是action请求 chain.doFilter(request, response); } else { request = prepare.wrapRequest(request); ActionMapping mapping = prepare.findActionMapping(request, response, true);
//创建ActionMapping对象,创建ActionMapping的过程要借助ActionMapper,如果ActionMapping对象不是null,将该对象放入request域中
//mapping = dispatcher.getContainer().getInstance(ActionMapper.class).getMapping(request, dispatcher.getConfigurationManager());
if (mapping == null) { boolean handled = execute.executeStaticResourceRequest(request, response); if (!handled) { chain.doFilter(request, response); } } else { execute.executeAction(request, response, mapping); } } } finally { prepare.cleanupRequest(request); } }
4.Dispatcher的serviceAction方法
在该方法中,获取Configuration对象,根据Configuration创建ActionProxy,将控制权交给ActionProxy,调用ActionProxy的execute()
public void serviceAction(HttpServletRequest request, HttpServletResponse response, ServletContext context, ActionMapping mapping) throws ServletException { Map<String, Object> extraContext = createContextMap(request, response, mapping, context); // 创建ValueStack的Map属性 // If there was a previous value stack, then create a new copy and pass it in to be used by the new Action ValueStack stack = (ValueStack) request.getAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY); boolean nullStack = stack == null; if (nullStack) { ActionContext ctx = ActionContext.getContext(); if (ctx != null) { stack = ctx.getValueStack(); } } if (stack != null) { extraContext.put(ActionContext.VALUE_STACK, valueStackFactory.createValueStack(stack)); } String timerKey = "Handling request from Dispatcher"; try { UtilTimerStack.push(timerKey); String namespace = mapping.getNamespace(); String name = mapping.getName(); String method = mapping.getMethod(); Configuration config = configurationManager.getConfiguration(); ActionProxy proxy = config.getContainer().getInstance(ActionProxyFactory.class).createActionProxy( namespace, name, method, extraContext, true, false); request.setAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY, proxy.getInvocation().getStack()); // if the ActionMapping says to go straight to a result, do it! if (mapping.getResult() != null) { Result result = mapping.getResult(); result.execute(proxy.getInvocation()); } else { proxy.execute(); } // If there was a previous value stack then set it back onto the request if (!nullStack) { request.setAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY, stack); } } catch (ConfigurationException e) { // WW-2874 Only log error if in devMode if(devMode) { String reqStr = request.getRequestURI(); if (request.getQueryString() != null) { reqStr = reqStr + "?" + request.getQueryString(); } LOG.error("Could not find action or result " + reqStr, e); } else { if (LOG.isWarnEnabled()) { LOG.warn("Could not find action or result", e); } } sendError(request, response, context, HttpServletResponse.SC_NOT_FOUND, e); } catch (Exception e) { sendError(request, response, context, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e); } finally { UtilTimerStack.pop(timerKey); } }
5.ActionProxy的execute方法
调用ActionInvocation的invoke方法
public String execute() throws Exception { ActionContext nestedContext = ActionContext.getContext(); ActionContext.setContext(invocation.getInvocationContext()); String retCode = null; String profileKey = "execute: "; try { UtilTimerStack.push(profileKey); retCode = invocation.invoke(); } finally { if (cleanupContext) { ActionContext.setContext(nestedContext); } UtilTimerStack.pop(profileKey); } return retCode; }
6.ActionInvocation的invoke方法
依次调用配置的所有拦截器的intercept方法
调用到最后一个拦截器时,调用invokeActionOnly方法
public String invoke() throws Exception { String profileKey = "invoke: "; try { UtilTimerStack.push(profileKey); if (executed) { throw new IllegalStateException("Action has already executed"); } if (interceptors.hasNext()) { final InterceptorMapping interceptor = (InterceptorMapping) interceptors.next(); String interceptorMsg = "interceptor: " + interceptor.getName(); UtilTimerStack.push(interceptorMsg); try { resultCode = interceptor.getInterceptor().intercept(DefaultActionInvocation.this); } finally { UtilTimerStack.pop(interceptorMsg); } } else { resultCode = invokeActionOnly(); } // this is needed because the result will be executed, then control will return to the Interceptor, which will // return above and flow through again if (!executed) { if (preResultListeners != null) { for (Object preResultListener : preResultListeners) { PreResultListener listener = (PreResultListener) preResultListener; String _profileKey = "preResultListener: "; try { UtilTimerStack.push(_profileKey); listener.beforeResult(this, resultCode); } finally { UtilTimerStack.pop(_profileKey); } } } // now execute the result, if we're supposed to if (proxy.getExecuteResult()) { executeResult(); } executed = true; } return resultCode; } finally { UtilTimerStack.pop(profileKey); } }
7.拦截器的Intercept方法
实现拦截器的功能
8.ActionInvocation的invokeActionOnly方法
根据配置的顺序,依次调用拦截器的intercept方法,当拦截器调用完之后,调用invokeActionOnly方法,再该方法中调用invokeAction方法,调用目标action方法
9.ActionInvocation的invokeAction方法
protected String invokeAction(Object action, ActionConfig actionConfig) throws Exception { String methodName = proxy.getMethod(); if (LOG.isDebugEnabled()) { LOG.debug("Executing action method = " + actionConfig.getMethodName()); } String timerKey = "invokeAction: " + proxy.getActionName(); try { UtilTimerStack.push(timerKey); boolean methodCalled = false; Object methodResult = null; Method method = null; try { method = getAction().getClass().getMethod(methodName, EMPTY_CLASS_ARRAY); } catch (NoSuchMethodException e) { // hmm -- OK, try doXxx instead try { String altMethodName = "do" + methodName.substring(0, 1).toUpperCase() + methodName.substring(1); method = getAction().getClass().getMethod(altMethodName, EMPTY_CLASS_ARRAY); } catch (NoSuchMethodException e1) { // well, give the unknown handler a shot if (unknownHandlerManager.hasUnknownHandlers()) { try { methodResult = unknownHandlerManager.handleUnknownMethod(action, methodName); methodCalled = true; } catch (NoSuchMethodException e2) { // throw the original one throw e; } } else { throw e; } } } if (!methodCalled) { methodResult = method.invoke(action, EMPTY_OBJECT_ARRAY); } return saveResult(actionConfig, methodResult); } catch (NoSuchMethodException e) { throw new IllegalArgumentException("The " + methodName + "() is not defined in action " + getAction().getClass() + ""); } catch (InvocationTargetException e) { // We try to return the source exception. Throwable t = e.getTargetException(); if (actionEventListener != null) { String result = actionEventListener.handleException(t, getStack()); if (result != null) { return result; } } if (t instanceof Exception) { throw (Exception) t; } else { throw e; } } finally { UtilTimerStack.pop(timerKey); } }
10.ActionInvocation的executeResult方法
invokeAction方法返回之后(表示目标action方法执行完成),调用executeResult方法,在该方法中调用Result的execute方法渲染结果
private void executeResult() throws Exception { result = createResult(); String timerKey = "executeResult: " + getResultCode(); try { UtilTimerStack.push(timerKey); if (result != null) { result.execute(this); } else if (resultCode != null && !Action.NONE.equals(resultCode)) { throw new ConfigurationException("No result defined for action " + getAction().getClass().getName() + " and result " + getResultCode(), proxy.getConfig()); } else { if (LOG.isDebugEnabled()) { LOG.debug("No result returned for action " + getAction().getClass().getName() + " at " + proxy.getConfig().getLocation()); } } } finally { UtilTimerStack.pop(timerKey); } }
11.结果返回之后的后续代码,将结果返回给客户端
涉及的对象
StrutsPrepareAndExecuteFilter
doFilter方法,(1)创建ActionContext对象(2)如果该请求是需要拦截的请求,根据请求创建ActionMapping对象(3)如果ActionMapping对象不是null,则最终调用Dispatcher的serviceAction方法
ActionMapping
该对象中存放的就是struts.xml中配置的一个一个的<action>
获取ActionMapping对象要借助ActionMapper对象
ActionMapper
Dispatcher
ActionProxy
通过ActionProxyFactory获取
Configuration
ConfigurationManager
ActionInvocation
Action
Result
总结:
请求首先经过StrutsPrepareAndExecuteFilter
调用dofilter方法
如果该请求是需要拦截的请求,通过ActionMapper获取ActionMapping,如果ActionMapping不是null,表明再struts.xml中配置了该请求对应的<action>
调用execute.executeAction(request, response, mapping);
调用dispatcher.serviceAction(request, response, servletContext, mapping);
先对值栈进行处理
通过ActionMapping、ConfigurationManager、Configuration、ActionFactory获取ActionProxy
将值栈放入request请求域中
调用proxy.execute();
调用retCode = invocation.invoke();
如果当期拦截器不是最后一个,调用拦截器的intercept方法 resultCode = interceptor.getInterceptor().intercept(DefaultActionInvocation.this); 在每个拦截器的intercept方法最后return invocation.invoke(); 以这样的方式依次调用拦截器,直到最后一个拦截器
如果当前拦截器是最后一个,调用ActionInvocation的invokeActionOnly方法 resultCode = invokeActionOnly();在拦截器调用完成之后,调用invokeAction方法执行目标Action方法 return invokeAction(getAction(), proxy.getConfig());
调用invokeAction(getAction(), proxy.getConfig());
String methodName = proxy.getMethod();
method = getAction().getClass().getMethod(methodName, EMPTY_CLASS_ARRAY);
methodResult = method.invoke(action, EMPTY_OBJECT_ARRAY);
调用executeResult()方法渲染结果
result = createResult();
result.execute(this);
依次执行每个拦截器的后续代码finally
执行后续代码,将结果返回