本文想通过分析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 request23 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 will28 // return above and flow through again29 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 to46 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 }
目前粗略地看了一下大体上的流程,具体还要继续分析里面的各种设计模式,设计思想。