init_CustomConfigurationProviders方式初始自定义的Provider,配置类全名和实现ConfigurationProvider接口,用逗号隔开即可。
 

Java代码 复制代码  收藏代码
  1. private void init_CustomConfigurationProviders() {   
  2.     String configProvs = initParams.get("configProviders");   
  3.     if (configProvs != null) {   
  4.         String[] classes = configProvs.split("\\s*[,]\\s*");   
  5.         for (String cname : classes) {   
  6.             try {   
  7.                 Class cls = ClassLoaderUtils.loadClass(cname, this.getClass());   
  8.                 ConfigurationProvider prov = (ConfigurationProvider)cls.newInstance();   
  9.                 configurationManager.addConfigurationProvider(prov);   
  10.             }   
  11.                
  12.         }   
  13.     }   
  14. }  

    private void init_CustomConfigurationProviders() {
        String configProvs = initParams.get("configProviders");
        if (configProvs != null) {
            String[] classes = configProvs.split("\\s*[,]\\s*");
            for (String cname : classes) {
                try {
                    Class cls = ClassLoaderUtils.loadClass(cname, this.getClass());
                    ConfigurationProvider prov = (ConfigurationProvider)cls.newInstance();
                    configurationManager.addConfigurationProvider(prov);
                }
                
            }
        }
    }


   好了,现在再回到FilterDispatcher,每次发送一个Request,FilterDispatcher都会调用doFilter方法。
 

Java代码 复制代码  收藏代码
  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.     ServletContext servletContext = getServletContext();   
  6.   
  7.     String timerKey = "FilterDispatcher_doFilter: ";   
  8.     try {   
  9.         ValueStack stack = dispatcher.getContainer().getInstance(ValueStackFactory.class).createValueStack();   
  10.         ActionContext ctx = new ActionContext(stack.getContext());   
  11.         ActionContext.setContext(ctx);   
  12.            
  13.         UtilTimerStack.push(timerKey);   
  14.         //根据content type来使用不同的Request封装,可以参见Dispatcher的wrapRequest   
  15.         request = prepareDispatcherAndWrapRequest(request, response);   
  16.         ActionMapping mapping;   
  17.         try {   
  18.             //根据url取得对应的Action的配置信息--ActionMapping,actionMapper是通过Container的inject注入的   
  19.             mapping = actionMapper.getMapping(request, dispatcher.getConfigurationManager());   
  20.         } catch (Exception ex) {   
  21.             log.error("error getting ActionMapping", ex);   
  22.             dispatcher.sendError(request, response, servletContext, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, ex);   
  23.             return;   
  24.         }   
  25.         //如果找不到对应的action配置,则直接返回。比如你输入***.jsp等等   
  26.         //这儿有个例外,就是如果path是以“/struts”开头,则到初始参数packages配置的包路径去查找对应的静态资源并输出到页面流中,当然.class文件除外。如果再没有则跳转到404   
  27.         if (mapping == null) {   
  28.             // there is no action in this request, should we look for a static resource?   
  29.             String resourcePath = RequestUtils.getServletPath(request);   
  30.   
  31.             if ("".equals(resourcePath) && null != request.getPathInfo()) {   
  32.                 resourcePath = request.getPathInfo();   
  33.             }   
  34.   
  35.             if (serveStatic && resourcePath.startsWith("/struts")) {   
  36.                 String name = resourcePath.substring("/struts".length());   
  37.                 findStaticResource(name, request, response);   
  38.             } else {   
  39.                 chain.doFilter(request, response);   
  40.             }   
  41.             return;   
  42.         }   
  43.         //正式开始Action的方法了   
  44.         dispatcher.serviceAction(request, response, servletContext, mapping);   
  45.   
  46.     } finally {   
  47.         try {   
  48.             ActionContextCleanUp.cleanUp(req);   
  49.         } finally {   
  50.             UtilTimerStack.pop(timerKey);   
  51.         }   
  52.     }   
  53. }  

    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 {
            ValueStack stack = dispatcher.getContainer().getInstance(ValueStackFactory.class).createValueStack();
            ActionContext ctx = new ActionContext(stack.getContext());
            ActionContext.setContext(ctx);
            
            UtilTimerStack.push(timerKey);
            //根据content type来使用不同的Request封装,可以参见Dispatcher的wrapRequest
            request = prepareDispatcherAndWrapRequest(request, response);
            ActionMapping mapping;
            try {
                //根据url取得对应的Action的配置信息--ActionMapping,actionMapper是通过Container的inject注入的
                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;
            }
            //如果找不到对应的action配置,则直接返回。比如你输入***.jsp等等
            //这儿有个例外,就是如果path是以“/struts”开头,则到初始参数packages配置的包路径去查找对应的静态资源并输出到页面流中,当然.class文件除外。如果再没有则跳转到404
            if (mapping == null) {
                // there is no action in this request, should we look for a static resource?
                String resourcePath = RequestUtils.getServletPath(request);

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

                if (serveStatic && resourcePath.startsWith("/struts")) {
                    String name = resourcePath.substring("/struts".length());
                    findStaticResource(name, request, response);
                } else {
                    chain.doFilter(request, response);
                }
                return;
            }
            //正式开始Action的方法了
            dispatcher.serviceAction(request, response, servletContext, mapping);

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


    Dispatcher类的serviceAction方法:
 

Java代码 复制代码  收藏代码
  1. public void serviceAction(HttpServletRequest request, HttpServletResponse response, ServletContext context,ActionMapping mapping) throws ServletException {   
  2.   
  3.     Map<String, Object> extraContext = createContextMap(request, response, mapping, context);   
  4.   
  5.     // If there was a previous value stack, then create a new copy and pass it in to be used by the new Action   
  6.     ValueStack stack = (ValueStack) request.getAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY);   
  7.     if (stack != null) {   
  8.         extraContext.put(ActionContext.VALUE_STACK, valueStackFactory.createValueStack(stack));   
  9.     }   
  10.   
  11.     String timerKey = "Handling request from Dispatcher";   
  12.     try {   
  13.         UtilTimerStack.push(timerKey);   
  14.         String namespace = mapping.getNamespace();   
  15.         String name = mapping.getName();   
  16.         String method = mapping.getMethod();   
  17.   
  18.         Configuration config = configurationManager.getConfiguration();   
  19.         ActionProxy proxy = config.getContainer().getInstance(ActionProxyFactory.class).createActionProxy(   
  20.                 namespace, name, method, extraContext, truefalse);   
  21.   
  22.         request.setAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY, proxy.getInvocation().getStack());   
  23.   
  24.         // if the ActionMapping says to go straight to a result, do it!   
  25.         if (mapping.getResult() != null) {   
  26.             Result result = mapping.getResult();   
  27.             result.execute(proxy.getInvocation());   
  28.         } else {   
  29.             proxy.execute();   
  30.         }   
  31.   
  32.         // If there was a previous value stack then set it back onto the request   
  33.         if (stack != null) {   
  34.             request.setAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY, stack);   
  35.         }   
  36.     } catch (ConfigurationException e) {   
  37.         LOG.error("Could not find action or result", e);   
  38.         sendError(request, response, context, HttpServletResponse.SC_NOT_FOUND, e);   
  39.     } catch (Exception e) {   
  40.         sendError(request, response, context, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e);   
  41.     } finally {   
  42.         UtilTimerStack.pop(timerKey);   
  43.     }   
  44. }  

    public void serviceAction(HttpServletRequest request, HttpServletResponse response, ServletContext context,ActionMapping mapping) throws ServletException {

        Map<String, Object> extraContext = createContextMap(request, response, mapping, context);

        // If there was a previous value stack, then create a new copy and pass it in to be used by the new Action
        ValueStack stack = (ValueStack) request.getAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY);
        if (stack != null) {
            extraContext.put(ActionContext.VALUE_STACK, valueStackFactory.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 proxy = config.getContainer().getInstance(ActionProxyFactory.class).createActionProxy(
                    namespace, name, method, extraContext, true, false);

            request.setAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY, proxy.getInvocation().getStack());

            // if the ActionMapping says to go straight to a result, do it!
            if (mapping.getResult() != null) {
                Result result = mapping.getResult();
                result.execute(proxy.getInvocation());
            } else {
                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) {
            sendError(request, response, context, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e);
        } finally {
            UtilTimerStack.pop(timerKey);
        }
    }


    第一句createContextMap()方法,该方法主要把Application、Session、Request的key value值拷贝到Map中,并放在HashMap<String,Object>中,可以参见createContextMap方法:
 

Java代码 复制代码  收藏代码
  1. public Map<String,Object> createContextMap(HttpServletRequest request, HttpServletResponse response,   
  2.         ActionMapping mapping, ServletContext context) {   
  3.   
  4.     // request map wrapping the http request objects   
  5.     Map requestMap = new RequestMap(request);   
  6.     // parameters map wrapping the http parameters.  ActionMapping parameters are now handled and applied separately   
  7.     Map params = new HashMap(request.getParameterMap());   
  8.     // session map wrapping the http session   
  9.     Map session = new SessionMap(request);   
  10.     // application map wrapping the ServletContext   
  11.     Map application = new ApplicationMap(context);   
  12.     Map<String,Object> extraContext = createContextMap(requestMap, params, session, application, request, response, context);   
  13.     extraContext.put(ServletActionContext.ACTION_MAPPING, mapping);   
  14.     return extraContext;   
  15. }  

    public Map<String,Object> createContextMap(HttpServletRequest request, HttpServletResponse response,
            ActionMapping mapping, ServletContext context) {

        // request map wrapping the http request objects
        Map requestMap = new RequestMap(request);
        // parameters map wrapping the http parameters.  ActionMapping parameters are now handled and applied separately
        Map params = new HashMap(request.getParameterMap());
        // session map wrapping the http session
        Map session = new SessionMap(request);
        // application map wrapping the ServletContext
        Map application = new ApplicationMap(context);
        Map<String,Object> extraContext = createContextMap(requestMap, params, session, application, request, response, context);
        extraContext.put(ServletActionContext.ACTION_MAPPING, mapping);
        return extraContext;
    }


    后面才是最主要的--ActionProxy,ActionInvocation。ActionProxy是Action的一个代理类,也就是说Action的调用是通过ActionProxy实现的,其实就是调用了ActionProxy.execute()方法,而该方法又调用了ActionInvocation.invoke()方法。归根到底,最后调用的是DefaultActionInvocation.invokeAction()方法。先看DefaultActionInvocation的init方法。
 

Java代码 复制代码  收藏代码
  1. public void init(ActionProxy proxy) {   
  2.     this.proxy = proxy;   
  3.     Map contextMap = createContextMap();   
  4.   
  5.     // Setting this so that other classes, like object factories, can use the ActionProxy and other   
  6.     // contextual information to operate   
  7.     ActionContext actionContext = ActionContext.getContext();   
  8.   
  9.     if(actionContext != null) {   
  10.         actionContext.setActionInvocation(this);   
  11.     }   
  12.     //创建Action,可Struts2里是每次请求都新建一个Action   
  13.     createAction(contextMap);   
  14.   
  15.     if (pushAction) {   
  16.         stack.push(action);   
  17.         contextMap.put("action", action);   
  18.     }   
  19.   
  20.     invocationContext = new ActionContext(contextMap);   
  21.     invocationContext.setName(proxy.getActionName());   
  22.   
  23.     // get a new List so we don't get problems with the iterator if someone changes the list   
  24.     List interceptorList = new ArrayList(proxy.getConfig().getInterceptors());   
  25.     interceptors = interceptorList.iterator();   
  26. }   
  27.   
  28. protected void createAction(Map contextMap) {   
  29.     // load action   
  30.     String timerKey = "actionCreate: "+proxy.getActionName();   
  31.     try {   
  32.         UtilTimerStack.push(timerKey);   
  33.         //这儿默认建立Action是StrutsObjectFactory,实际中我使用的时候都是使用Spring创建的Action,这个时候使用的是SpringObjectFactory   
  34.         action = objectFactory.buildAction(proxy.getActionName(), proxy.getNamespace(), proxy.getConfig(), contextMap);   
  35.     }    
  36.     ..   
  37.     } finally {   
  38.         UtilTimerStack.pop(timerKey);   
  39.     }   
  40.   
  41.     if (actionEventListener != null) {   
  42.         action = actionEventListener.prepare(action, stack);   
  43.     }   
  44. }