第一個環節是FilterDispatcher,過濾、包裝請求,調用dispatcher的serviceAction方法。主要代碼如下:

 1UtilTimerStack.push(timerKey);
 2            request = prepareDispatcherAndWrapRequest(request, response);
 3            ActionMapping mapping;
 4            try {
 5                mapping = actionMapper.getMapping(request, dispatcher.getConfigurationManager());
 6            }
 catch (Exception ex) {
 7                LOG.error("error getting ActionMapping", ex);
 8                dispatcher.sendError(request, response, servletContext, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, ex);
 9                return;
10            }

11
12            if (mapping == null{
13                // there is no action in this request, should we look for a static resource?
14                String resourcePath = RequestUtils.getServletPath(request);
15
16                if ("".equals(resourcePath) && null != request.getPathInfo()) {
17                    resourcePath = request.getPathInfo();
18                }

19
20                if (serveStatic && resourcePath.startsWith("/struts")) {
21                    String name = resourcePath.substring("/struts".length());
22                    findStaticResource(name, request, response);
23                }
 else {
24                    // this is a normal request, let it pass through
25                    chain.doFilter(request, response);
26                }

27                // The framework did its job here
28                return;
29            }

30
31            dispatcher.serviceAction(request, response, servletContext, mapping);

可以看到這里面調用actionMapper找到了當前請求對應的actionMapping。然后就是dispatcher.serviceAction這個方法了。可以想象肯定是找到對應的Action類,執行相應的action方法。Dispatcher類的serviceAction方法主要代碼如下:

 1UtilTimerStack.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 proxy = config.getContainer().getInstance(ActionProxyFactory.class).createActionProxy(
 8                    namespace, name, extraContext, truefalse);
 9            proxy.setMethod(method);
10            request.setAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY, proxy.getInvocation().getStack());
11
12            // if the ActionMapping says to go straight to a result, do it!
13            if (mapping.getResult() != null{
14                Result result = mapping.getResult();
15                result.execute(proxy.getInvocation());
16            }
 else {
17                proxy.execute();
18            }

19
20            // If there was a previous value stack then set it back onto the request
21            if (stack != null{
22                request.setAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY, stack);
23            }

可以看到,其中從configurationManager中找到config,在利用config,通過ActionProxyFactory創建了合適的ActionProxy對象。后面就是判斷如果當前的mapping存在result,那么直接返回result的執行結果,否則執行proxy.execute。前者的含義我猜是處理某些不需要Action的請求的時候用到的。具體要調用最后的Action中的什么方法也是在這個時候確定的(proxy.setMethod(....))。

上面的代碼中,實際上是使用StrutsActionProxyFactory類的createActionProxy方法來創建ActionProxy的。這個方法如下:

1 ActionProxy proxy = new StrutsActionProxy(namespace, actionName, extraContext, executeResult, cleanupContext);
2        container.inject(proxy);
3        proxy.prepare();
4        return proxy;

可以看到創建proxy之后,調用了proxy的prepare方法,于是看DefaultActionProxy類的prepare方法中有這樣的代碼:

1invocation = new DefaultActionInvocation(objectFactory, unknownHandler, this, extraContext, true, actionEventListener);

實際上是創建了這個proxy中的invocation對象,這個對象很重要,后面是順著這個對象的invoke方法去執行我們寫的Action中的具體方法的。

回頭再去看上面第二段代碼中,創建proxy之后,調用了proxy的execute方法,這個里面寫得很簡單:

 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    }

就是執行了invocation的invoke方法。而這個invocation是哪里來的,我們也已經很清楚了。這個invocation類實際上是DefaultActionInvocation類的一個實例。其invoke方法如下:

 1if (executed) {
 2                throw new IllegalStateException("Action has already executed");
 3            }

 4
 5            if (interceptors.hasNext()) {
 6                final InterceptorMapping interceptor = (InterceptorMapping) interceptors.next();
 7                UtilTimerStack.profile("interceptor: "+interceptor.getName(), 
 8                        new UtilTimerStack.ProfilingBlock<String>() {
 9                            public String doProfiling() throws Exception {
10                                resultCode = interceptor.getInterceptor().intercept(DefaultActionInvocation.this);
11                                return null;
12                            }

13                }
);
14            }
 else {
15                resultCode = invokeActionOnly();
16            }

17
18            // this is needed because the result will be executed, then control will return to the Interceptor, which will
19            // return above and flow through again
20            if (!executed) {
21                if (preResultListeners != null{
22                    for (Iterator iterator = preResultListeners.iterator();
23                        iterator.hasNext();) {
24                        PreResultListener listener = (PreResultListener) iterator.next();
25                        
26                        String _profileKey="preResultListener: ";
27                        try {
28                            UtilTimerStack.push(_profileKey);
29                            listener.beforeResult(this, resultCode);
30                        }

31                        finally {
32                            UtilTimerStack.pop(_profileKey);
33                        }

34                    }

35                }

36
37                // now execute the result, if we're supposed to
38                if (proxy.getExecuteResult()) {
39                    executeResult();
40                }

41
42                executed = true;
43            }

44
45            return resultCode;

可以看到,其中對于有沒有interceptor的情況作了分別處理。有interceptor的情況則調用第一個interceptor的intercept方法,intercepter的執行應該是一個鏈式的,所以這里只是調用第一個(這個事情不確定,沒看interceptor里面的內容)。不論如何,最后都會調用到invocation的invokeAction方法,這里面基本上就是個反射,調用我們寫的action類的相應方法了。值得注意的是上面的代碼中,最后判斷了proxy是否需要使用result,如果需要,那么調用executeResult方法,其中主要內容就是調用相應result對象的execute方法,這里是真個流程的最后一步。

其中:命令模式、代理模式