//任何请求都会先执行Filter.doFilter方法
protected PrepareOperations prepare; protected ExecuteOperations execute; protected List<Pattern> excludedPatterns = null; 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);② prepare.assignDispatcherToThread();③ if ( excludedPatterns != null && prepare.isUrlExcluded(request, excludedPatterns)) { chain.doFilter(request, response); } else { request = prepare.wrapRequest(request); 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);⑤ } } } finally { prepare.cleanupRequest(request); } }
//① prepare.setEncodingAndLocale方法名可以看出,是设置request的编码方式和reponse的Locale,具体内容不细分析
//② prepare.createActionContext创建当前request线程的ActionContext,Threadlocal修饰的线程隔离变量
//③prepare.assignDispatcherToThread设置当前request线程的Dispather, Threadlocal维护的线程隔离变量
//④和⑤是分析request的uri,根据namespace和action,以及method,得到映射的jsp
public ActionMapping findActionMapping(HttpServletRequest request, HttpServletResponse response) { return findActionMapping(request, response, false); } public ActionMapping findActionMapping(HttpServletRequest request, HttpServletResponse response, boolean forceLookup) { ActionMapping mapping = (ActionMapping) request.getAttribute(STRUTS_ACTION_MAPPING_KEY); if (mapping == null || forceLookup) { try { 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; }
public Container getContainer() { if (ContainerHolder.get() != null) { return ContainerHolder.get(); } ConfigurationManager mgr = getConfigurationManager(); if (mgr == null) { throw new IllegalStateException("The configuration manager shouldn't be null"); } else { Configuration config = mgr.getConfiguration(); if (config == null) { throw new IllegalStateException("Unable to load configuration"); } else { Container container = config.getContainer(); ContainerHolder.store(container); return container; } } } public ConfigurationManager getConfigurationManager() { return configurationManager; }
public synchronized Configuration getConfiguration() { if (configuration == null) { setConfiguration(createConfiguration(defaultFrameworkBeanName)); try { configuration.reloadContainer(getContainerProviders()); } catch (ConfigurationException e) { setConfiguration(null); throw new ConfigurationException("Unable to load configuration.", e); } } else { conditionalReload(); } return configuration; }
public Container getContainer() { return container; } public synchronized List<PackageProvider> reloadContainer(List<ContainerProvider> providers) throws ConfigurationException { …… ContainerBuilder builder = new ContainerBuilder(); …… container = builder.create(false); //实际上是ContainerImpl
public Container create(boolean loadSingletons) { <span style="color:#0800;"><span style="font-family:宋体;"> </span></span>ensureNotCreated(); created = true; final ContainerImpl container = new ContainerImpl( new HashMap<Key<?>, InternalFactory<?>>(factories)); if (loadSingletons) { container.callInContext(new ContainerImpl.ContextualCallable<Void>() { public Void call(InternalContext context) { <span style="color:#0800;"><span style="font-family:宋体;"> </span></span> for (InternalFactory<?> factory : singletonFactories) { factory.create(context); <span style="color:#0800;"><span style="font-family:宋体;"> </span></span> } <span style="color:#0800;"><span style="font-family:宋体;"> </span></span> return null; } <span style="color:#0800;"><span style="font-family:宋体;"> </span></span>}); } container.injectStatics(staticInjections); return container; }
public <T> T getInstance( final Class<T> type ) { return callInContext(new ContextualCallable<T>() { public T call( InternalContext context ) { return getInstance(type, context); } }); }
//这里从容器中拿到DefaultActionMapper的实例
public ActionMapping getMapping(HttpServletRequest request, ConfigurationManager configManager) { 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; } parseNameAndNamespace(uri, mapping, configManager); handleSpecialParameters(request, mapping); return parseActionName(mapping); }
//getUri取得当前访问路径URI
//dropExtension去掉URI后面的.action后缀
//parseNameAndNamespace获取NameSpace和Action Name
//parseActionName判断是否支持动态方法调用
public void executeAction(HttpServletRequest request, HttpServletResponse response, ActionMapping mapping) throws ServletException { dispatcher.serviceAction(request, response, servletContext, mapping); }
public void serviceAction(HttpServletRequest request, HttpServletResponse response, ServletContext context, ActionMapping mapping) throws ServletException { ...... Configuration config = configurationManager.getConfiguration(); ActionProxy proxy = config.getContainer().getInstance(ActionProxyFactory.class).createActionProxy(namespace, name, method, extraContext, true, false); ...... if (mapping.getResult() != null) { Result result = mapping.getResult(); result.execute(proxy.getInvocation()); } else { proxy.execute(); } ......
//Container.getInstance(ActionProxyFactory)获取ActionProxyFactory类实例StrutsActionProxyFactory
//struts-default.xml中定义了
<bean type="com.opensymphony.xwork2.ActionProxyFactory" name="struts" class="org.apache.struts2.impl.StrutsActionProxyFactory"/>
调用父类DefaultActionProxyFactory.createActionProxy方法
public ActionProxy createActionProxy(String namespace, String actionName, String methodName, Map<String, Object> extraContext, boolean executeResult, boolean cleanupContext) { ActionInvocation inv = new DefaultActionInvocation(extraContext, true); container.inject(inv); return createActionProxy(inv, namespace, actionName, methodName, executeResult, cleanupContext); }
再调用自已重载的createActionProxy方法
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); proxy.prepare(); return proxy; }
//这里采用了动态代理,使用StrutsActionProxy代理了ActionInvocation,
//proxy的prepare最后执行ActionInvocation.init
//proxy的execute最后执行ActionInvocation.Invoke
protected void prepare() { super.prepare(); } 调用父类DefaultActionProxy的prepare方法 protected void prepare() { ...... resolveMethod();//判断是否设置method 为默认值execute invocation.init(this); ......
public void init(ActionProxy proxy) { <span style="color:#0800;"><span style="font-family:宋体;"> </span></span>...... createAction(contextMap);//根据Namespace, ActionName等参数得到Action实例 ...... List<InterceptorMapping> interceptorList = new ArrayList<InterceptorMapping>(proxy.getConfig().getInterceptors()); interceptors = interceptorList.iterator();//得到interceptoerList } protected void createAction(Map<String, Object> contextMap) { ...... action = objectFactory.buildAction(proxy.getActionName(), proxy.getNamespace(), proxy.getConfig(), contextMap); ...... }
public String execute() throws Exception { ...... return invocation.invoke(); }
public String invoke() throws Exception { try { ...... <span style="color:#0800;"><span style="font-family:宋体;"> </span></span> if (interceptors.hasNext()) { <span style="color:#0800;"><span style="font-family:宋体;"> </span></span>final InterceptorMapping interceptor = interceptors.next(); resultCode = interceptor.getInterceptor().intercept(DefaultActionInvocation.this); } else { resultCode = invokeActionOnly(); } ...... if (!executed) { <span style="color:#0800;"><span style="font-family:宋体;"> </span></span>if (proxy.getExecuteResult()) { executeResult(); <span style="color:#0800;"><span style="font-family:宋体;"> </span></span>} <span style="color:#0800;"><span style="font-family:宋体;"> </span></span>executed = true <span style="color:#0800;"><span style="font-family:宋体;"> </span></span>return resultCode; ...... } //先执行Action的拦截器,当所有的拦截器执行完,再执行Action里面的method,最后执行result public String invokeActionOnly() throws Exception { return invokeAction(getAction(), proxy.getConfig()); } protected String invokeAction(Object action, ActionConfig actionConfig) throws Exception { <span style="color:#0800;"><span style="font-family:宋体;"> </span></span>String methodName = proxy.getMethod(); <span style="color:#0800;"><span style="font-family:宋体;"> </span></span>Object methodResult = null; <span style="color:#0800;"><span style="font-family:宋体;"> </span></span>Method method = null; ...... <span style="color:#0800;"><span style="font-family:宋体;"> </span></span>method = getAction().getClass().getMethod(methodName, EMPTY_CLASS_ARRAY); <span style="color:#0800;"><span style="font-family:宋体;"> </span></span>if (!methodCalled) { methodResult = method.invoke(action, EMPTY_OBJECT_ARRAY);//利用反射,执行action的methold <span style="color:#0800;"><span style="font-family:宋体;"> </span></span>} return saveResult(actionConfig, methodResult); } private void executeResult() throws Exception { <span style="color:#0800;"><span style="font-family:宋体;"> </span></span>result = createResult(); ...... <span style="color:#0800;"><span style="font-family:宋体;"> </span></span>result.execute(this); ...... } 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();//获取当前action的所有ResultConfig ...... ResultConfig resultConfig = null; ...... resultConfig = results.get(resultCode);//根据resultCode获取对应的resultConfig //resultConfig = results.get("*"); if (resultConfig != null) { return objectFactory.buildResult(resultConfig, invocationContext.getContextMap());//根据resultConfig创建对应的Result ...... return null; }
//最后执行对应的Result,struts默认的并且最常见的result就是ServletDispatcherResult
//struts-default.xml定义了
<result-types>
......
<result-type name="dispatcher" class="org.apache.struts2.dispatcher.ServletDispatcherResult" default="true"/>
......
调用父类StrutsResultSupport.execute
public void execute(ActionInvocation invocation) throws Exception { lastFinalLocation = conditionalParse(location, invocation); doExecute(lastFinalLocation, invocation); }
调用自身的doExecute方法
public void doExecute(String finalLocation, ActionInvocation invocation) throws Exception { <span style="color:#0800;"><span style="font-family:宋体;"> </span></span>...... <span style="color:#0800;"><span style="font-family:宋体;"> </span></span>PageContext pageContext = ServletActionContext.getPageContext(); <span style="color:#0800;"><span style="font-family:宋体;"> </span></span>if (pageContext != null) { pageContext.include(finalLocation); <span style="color:#0800;"><span style="font-family:宋体;"> </span></span>} else { HttpServletRequest request = ServletActionContext.getRequest(); HttpServletResponse response = ServletActionContext.getResponse(); RequestDispatcher dispatcher = request.getRequestDispatcher(finalLocation); ...... if (!insideActionTag && !response.isCommitted() && (request.getAttribute("javax.servlet.include.servlet_path") == null)) { <span style="color:#0800;"><span style="font-family:宋体;"> </span></span>request.setAttribute("struts.view_uri", finalLocation); request.setAttribute("struts.request_uri", request.getRequestURI()); dispatcher.forward(request, response);//forward给对应的jsp } else { <span style="color:#0800;"><span style="font-family:宋体;"> </span></span>dispatcher.include(request, response); } <span style="color:#0800;"><span style="font-family:宋体;"> </span></span>} }