FilterDispatcher代码分析

在FilterDispatcher中首先关注的方法是init()和doFilter(),两个有用的局部变量(或者状态)
private FilterConfig filterConfig;
protected Dispatcher dispatcher;

filterConfig用来向filter传递信息,提供了四个方法:
public abstract java.lang.String getFilterName();
public abstract javax.servlet.ServletContext getServletContext();
public abstract java.lang.String getInitParameter(java.lang.String arg0);
public abstract java.util.Enumeration getInitParameterNames();

dispatcher做了FilterDispatcher大部分的工作。
首先来看init方法:
    public void init(FilterConfig filterConfig) throws ServletException {
    	 this.filterConfig = filterConfig;
    	 //把filterConfig中的parameters和servletContext传递给new Dispatcher(filterConfig.getServletContext(), params)
        dispatcher = createDispatcher(filterConfig);
        //加载各种配置
        dispatcher.init();
       
        String param = filterConfig.getInitParameter("packages");
        String packages = DEFAULT_STATIC_PACKAGES;
        if (param != null) {
            packages = param + " " + packages;
        }
        this.pathPrefixes = parse(packages);
    }


   public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {


        HttpServletRequest request = (HttpServletRequest) req;
        HttpServletResponse response = (HttpServletResponse) res;
        ServletContext servletContext = getServletContext();

        String timerKey = "FilterDispatcher_doFilter: ";
        try {
            UtilTimerStack.push(timerKey);
            request = prepareDispatcherAndWrapRequest(request, response);
            ActionMapping mapping;//ActionMapping有四个字段 method, name, namespace,params, result对应着XML配置文件
            try {
                //装配mappings
                mapping = actionMapper.getMapping(request, dispatcher.getConfigurationManager());
            } catch (Exception ex) {
                LOG.error("error getting ActionMapping", ex);
                dispatcher.sendError(request, response, servletContext, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, ex);
                return;
            }
             // 如果mapping是空的,则去找static的内容
            if (mapping == null) {
               
                String resourcePath = RequestUtils.getServletPath(request);

                if ("".equals(resourcePath) && null != request.getPathInfo()) {
                    resourcePath = request.getPathInfo();
                }

                if (serveStatic && resourcePath.startsWith("/struts")) {
                    findStaticResource(resourcePath, findAndCheckResources(resourcePath), request, response);
                } else {
                    // this is a normal request, let it pass through
                    chain.doFilter(request, response);
                }
                // The framework did its job here
                return;
            }
            //这个方法是关键
            dispatcher.serviceAction(request, response, servletContext, mapping);

        } finally {
            try {
                ActionContextCleanUp.cleanUp(req);
            } finally {
                UtilTimerStack.pop(timerKey);
            }
        }
    }

我们再来查看Dispatcher中的serviceAction。
   public void serviceAction(HttpServletRequest request, HttpServletResponse response, ServletContext context,
                              ActionMapping mapping) throws ServletException {

        //创建上下文,extraContext中包括parameterMap, sessionMap, applicationMap, locale, request, response, servletContext等等
        Map<String, Object> extraContext = createContextMap(request, response, mapping, context);

        //如果request之前有value stack,则复制一个并把它放到上下文中。        
        ValueStack stack = (ValueStack) request.getAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY);
        if (stack != null) {
            extraContext.put(ActionContext.VALUE_STACK, ValueStackFactory.getFactory().createValueStack(stack));
        }

        String timerKey = "Handling request from Dispatcher";
        try {
            UtilTimerStack.push(timerKey);
            String namespace = mapping.getNamespace();
            String name = mapping.getName();
            String method = mapping.getMethod();

            Configuration config = configurationManager.getConfiguration();
            //利用工厂方法新建一个ActionProxy,它提供诸多代理方法。
            ActionProxy proxy = config.getContainer().getInstance(ActionProxyFactory.class).createActionProxy(
                    namespace, name, extraContext, true, false);
            proxy.setMethod(method);
            request.setAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY, proxy.getInvocation().getStack());

            // 如果mapping中定义了Result,则运行这个Result。Result还是非常值得一讲的
            if (mapping.getResult() != null) {
                Result result = mapping.getResult();
                result.execute(proxy.getInvocation());
            } else {
                //没有则运行execute,即调用Invocation.invoke()
                proxy.execute();
            }

            // If there was a previous value stack then set it back onto the request
            if (stack != null) {
                request.setAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY, stack);
            }
        } catch (ConfigurationException e) {
            LOG.error("Could not find action or result", e);
            sendError(request, response, context, HttpServletResponse.SC_NOT_FOUND, e);
        } catch (Exception e) {
            throw new ServletException(e);
        } finally {
            UtilTimerStack.pop(timerKey);
        }
    }

public interface ActionProxy {

    /** 在所有的依赖都配置好调用,在DefaultActionProxyFactory.createActionProxy中使用 */
    void prepare() throws Exception;
    
    /** @return 返回所代理的对象 */
    Object getAction();

    /** @return 返回所代理的对象的名字 */
    String getActionName();

    /** @return ActionProxy产生所借助的ActionConfig */
    ActionConfig getConfig();

    /** 设置是否在运行完Action之后运行Action所返回的Result */
    void setExecuteResult(boolean executeResult);

    /** @return the status of whether the ActionProxy is set to execute the Result after the Action is executed
     */
    boolean getExecuteResult();

    /** @return the ActionInvocation:表示Action的运行状态,包括Interceptors和Action的实例 */
    ActionInvocation getInvocation();

    /**
     * @return the namespace the ActionConfig for this ActionProxy is mapped to
     */
    String getNamespace();

    /**
     * 运行ActionProxy. 把ActionContext 设置为 ActionInvocation中的 ActionContext
     * 关键还是调用ActionInvocation.invoke()。
     * DefaultActionProxy中的实现
     *public String execute() throws Exception {
     *   ActionContext nestedContext = ActionContext.getContext();
     *   ActionContext.setContext(invocation.getInvocationContext());

     *   String retCode = null;

     *   String profileKey = "execute: ";
     *   try {
     *   	UtilTimerStack.push(profileKey);
        	
     *       retCode = invocation.invoke();
     *   } finally {
     *       if (cleanupContext) {
     *           ActionContext.setContext(nestedContext);
     *       }
     *       UtilTimerStack.pop(profileKey);
     *   }

     *   return retCode;
     *}
     */
    String execute() throws Exception;

    /** 设置Invocation中的Method的,如果空的话就用execute。 */
    void setMethod(String method);

    /**
     * Returns the method to execute, or null if no method has been specified (meaning "execute" will be invoked)
     */
    String getMethod();
    
}



再来看一下ActionInvocation.invoke()的实现:
   public String invoke() throws Exception {
    	String profileKey = "invoke: ";
    	try {
    		UtilTimerStack.push(profileKey);
    		//如果运行过了,就抛出异常
    		if (executed) {
    			throw new IllegalStateException("Action has already executed");
    		}
                //运行Interceptor
    		if (interceptors.hasNext()) {
    			final InterceptorMapping interceptor = (InterceptorMapping) interceptors.next();
                        //UtilTimerStack.profile()即
        /*public static <T> T profile(String name, ProfilingBlock<T> block) throws Exception {
    	UtilTimerStack.push(name);
    	try {
    		return block.doProfiling();
    	}
    	finally {
    		UtilTimerStack.pop(name);
    	}
    }*/
    			UtilTimerStack.profile("interceptor: "+interceptor.getName(), 
    					new UtilTimerStack.ProfilingBlock<String>() {
							public String doProfiling() throws Exception {
				    			resultCode = interceptor.getInterceptor().intercept(DefaultActionInvocation.this);
				    			return null;
							}
    			});
    		} else {
    			resultCode = invokeActionOnly();
    		}

    		// this is needed because the result will be executed, then control will return to the Interceptor, which will
    		// return above and flow through again
  
[color=red]没看懂,好像是由于在下面还要调用result.execute(ActionInvocation),那么还是有可能再次调用这个地方?[/color]
    		if (!executed) {
    			if (preResultListeners != null) {
    				for (Iterator iterator = preResultListeners.iterator();
    					iterator.hasNext();) {
    					PreResultListener listener = (PreResultListener) iterator.next();
    					
    					String _profileKey="preResultListener: ";
    					try {
    						UtilTimerStack.push(_profileKey);
    						listener.beforeResult(this, resultCode);
    					}
    					finally {
    						UtilTimerStack.pop(_profileKey);
    					}
    				}
    			}

    			// now execute the result, if we're supposed to
    			if (proxy.getExecuteResult()) {
                                //调用result.execute(ActionInvocation);
    				executeResult();
    			}

    			executed = true;
    		}

    		return resultCode;
    	}
    	finally {
    		UtilTimerStack.pop(profileKey);
    	}
    }

猜你喜欢

转载自jfar.iteye.com/blog/1038712