init_CustomConfigurationProviders方式初始自定义的Provider,配置类全名和实现ConfigurationProvider接口,用逗号隔开即可。
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方法。
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方法:
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方法:
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方法。