第一个环节是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, true, false);
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方法,这里是真个流程的最后一步。
其中:命令模式、代理模式