struts2源码分析之流程
本文想通过分析struts2的源码来理解官方的流程图。
官方流程图如下:
流程步骤如下:
(1),首先根据web.xml的配置,当启动server时,会调用org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter过滤器的init()方法。
1 public void init(FilterConfig filterConfig) throws ServletException { 2 // 初始化InitOperations对象 3 InitOperations init = new InitOperations(); 4 // 定义Dispatcher 5 Dispatcher dispatcher = null; 6 try { 7 // 初始化FilterHostConfig对象 8 FilterHostConfig config = new FilterHostConfig(filterConfig); 9 // 初始化struts2的log工具 10 init.initLogging(config); 11 // 初始化dispatcher实例 12 dispatcher = init.initDispatcher(config); 13 init.initStaticContentLoader(config, dispatcher); 14 15 prepare = new PrepareOperations(filterConfig.getServletContext(), dispatcher); 16 execute = new ExecuteOperations(filterConfig.getServletContext(), dispatcher); 17 this.excludedPatterns = init.buildExcludedPatternsList(dispatcher); 18 19 postInit(dispatcher, filterConfig); 20 } finally { 21 if (dispatcher != null) { 22 dispatcher.cleanUpAfterInit(); 23 } 24 init.cleanup(); 25 } 26 }
(2),初始化完成之后,根据浏览器访问地址,开始调用StrutsPrepareAndExecuteFilter的doFilter()方法
1 public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException { 2 3 HttpServletRequest request = (HttpServletRequest) req; 4 HttpServletResponse response = (HttpServletResponse) res; 5 6 try { 7 // 设置request的encoding以及response的locale属性 8 prepare.setEncodingAndLocale(request, response); 9 // 创建ActionContext对象 10 prepare.createActionContext(request, response); 11 // 将dispatcher绑定到ThreadLocal上 12 prepare.assignDispatcherToThread(); 13 if (excludedPatterns != null && prepare.isUrlExcluded(request, excludedPatterns)) { 14 chain.doFilter(request, response); 15 } else { 16 request = prepare.wrapRequest(request); 17 // 创建ActionMapping对象 18 ActionMapping mapping = prepare.findActionMapping(request, response, true); 19 if (mapping == null) { 20 boolean handled = execute.executeStaticResourceRequest(request, response); 21 if (!handled) { 22 chain.doFilter(request, response); 23 } 24 } else { 25 // 去执行对应的Action类 26 execute.executeAction(request, response, mapping); 27 } 28 } 29 } finally { 30 prepare.cleanupRequest(request); 31 } 32 }
(3),具体调用方法是在Dispatcher类的serviceAction()方法中:
1 UtilTimerStack.push(timerKey); 2 String namespace = mapping.getNamespace(); 3 String name = mapping.getName(); 4 String method = mapping.getMethod(); 5 6 Configuration config = configurationManager.getConfiguration(); 7 // 创建ActionProxy实例 8 ActionProxy proxy = config.getContainer().getInstance(ActionProxyFactory.class).createActionProxy( 9 namespace, name, method, extraContext, true, false); 10 11 request.setAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY, proxy.getInvocation().getStack()); 12 13 // if the ActionMapping says to go straight to a result, do it! 14 if (mapping.getResult() != null) { 15 Result result = mapping.getResult(); 16 result.execute(proxy.getInvocation()); 17 } else { 18 // 调用对应的Action方法 19 proxy.execute(); 20 } 21 22 // If there was a previous value stack then set it back onto the request 23 if (!nullStack) { 24 request.setAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY, stack); 25 }
(4),接下来去DefaultActionProxy类中执行execute()方法:
1 public String execute() throws Exception { 2 ActionContext nestedContext = ActionContext.getContext(); 3 ActionContext.setContext(invocation.getInvocationContext()); 4 5 String retCode = null; 6 7 String profileKey = "execute: "; 8 try { 9 UtilTimerStack.push(profileKey); 10 // 此处再调用DefaultActionInvocation类的invoke方法 11 retCode = invocation.invoke(); 12 } finally { 13 if (cleanupContext) { 14 ActionContext.setContext(nestedContext); 15 } 16 UtilTimerStack.pop(profileKey); 17 } 18 19 return retCode; 20 }
(5),执行DefaultActionInvocation类的invoke方法:
1 public String invoke() throws Exception { 2 String profileKey = "invoke: "; 3 try { 4 UtilTimerStack.push(profileKey); 5 6 if (executed) { 7 throw new IllegalStateException("Action has already executed"); 8 } 9 10 // 此处先开始执行拦截器,只要拦截器链还没执行完,就会一直执行 11 // 此invoke方法 12 if (interceptors.hasNext()) { 13 final InterceptorMapping interceptor = interceptors.next(); 14 String interceptorMsg = "interceptor: " + interceptor.getName(); 15 UtilTimerStack.push(interceptorMsg); 16 try { 17 resultCode = interceptor.getInterceptor().intercept(DefaultActionInvocation.this); 18 } 19 finally { 20 UtilTimerStack.pop(interceptorMsg); 21 } 22 } else { 23 // 当所有拦截器都执行完成之后,执行invokeActionOnly()方法。 24 resultCode = invokeActionOnly(); 25 } 26 27 // this is needed because the result will be executed, then control will return to the Interceptor, which will 28 // return above and flow through again 29 if (!executed) { 30 if (preResultListeners != null) { 31 for (Object preResultListener : preResultListeners) { 32 PreResultListener listener = (PreResultListener) preResultListener; 33 34 String _profileKey = "preResultListener: "; 35 try { 36 UtilTimerStack.push(_profileKey); 37 listener.beforeResult(this, resultCode); 38 } 39 finally { 40 UtilTimerStack.pop(_profileKey); 41 } 42 } 43 } 44 45 // now execute the result, if we're supposed to 46 if (proxy.getExecuteResult()) { 47 // 此处返回对应的result结果给客户端 48 executeResult(); 49 } 50 51 executed = true; 52 } 53 54 return resultCode; 55 } 56 finally { 57 UtilTimerStack.pop(profileKey); 58 } 59 }
目前粗略地看了一下大体上的流程,具体还要继续分析里面的各种设计模式,设计思想。