public void init() throws ServletException { // Wraps the entire initialization in a try/catch to better handle // unexpected exceptions and errors to provide better feedback // to the developer try { initInternal(); initOther(); initServlet(); getServletContext().setAttribute(Globals.ACTION_SERVLET_KEY, this); initModuleConfigFactory(); // Initialize modules as needed ModuleConfig moduleConfig = initModuleConfig("", config); initModuleMessageResources(moduleConfig); initModuleDataSources(moduleConfig); initModulePlugIns(moduleConfig); moduleConfig.freeze(); Enumeration names = getServletConfig().getInitParameterNames(); while (names.hasMoreElements()) { String name = (String) names.nextElement(); if (!name.startsWith("config/")) { continue; } String prefix = name.substring(6); moduleConfig = initModuleConfig (prefix, getServletConfig().getInitParameter(name)); initModuleMessageResources(moduleConfig); initModuleDataSources(moduleConfig); initModulePlugIns(moduleConfig); moduleConfig.freeze(); } this.initModulePrefixes(this.getServletContext()); this.destroyConfigDigester(); } catch (UnavailableException ex) { throw ex; } catch (Throwable t) { // The follow error message is not retrieved from internal message // resources as they may not have been able to have been // initialized log.error("Unable to initialize Struts ActionServlet due to an " + "unexpected exception or error thrown, so marking the " + "servlet as unavailable. Most likely, this is due to an " + "incorrect or missing library dependency.", t); throw new UnavailableException(t.getMessage()); } }
该方法中initModuleConfig是配置信息的加载方法,它没掉用了两次:
//用于加载struts必须的配置struts-config.xml
ModuleConfig moduleConfig = initModuleConfig("", config); java
//用于加载配其余struts配置文件
moduleConfig = initModuleConfig
(prefix, getServletConfig().getInitParameter(name)); web
从以上代码能够看出,不一样的struts配置文件确定是根据参数进行区分了,其中prefix是web.xml中struts配置信息去掉“config/”以后param-name,下面配置信息中的prefix为page/user apache
<!-- 用户管理配置文件 --> <init-param> <param-name>config/page/user</param-name> <param-value> /WEB-INF/config/struts/module/struts-user.xml </param-value> </init-param>
如何区分和保存,看下面的代码: app
protected ModuleConfig initModuleConfig(String prefix, String paths) throws ServletException { // :FIXME: Document UnavailableException? (Doesn't actually throw anything) if (log.isDebugEnabled()) { log.debug( "Initializing module path '" + prefix + "' configuration from '" + paths + "'"); } // Parse the configuration for this module ModuleConfigFactory factoryObject = ModuleConfigFactory.createFactory(); ModuleConfig config = factoryObject.createModuleConfig(prefix); // Configure the Digester instance we will use Digester digester = initConfigDigester(); // Process each specified resource path while (paths.length() > 0) { digester.push(config); String path = null; int comma = paths.indexOf(','); if (comma >= 0) { path = paths.substring(0, comma).trim(); paths = paths.substring(comma + 1); } else { path = paths.trim(); paths = ""; } if (path.length() < 1) { break; } this.parseModuleConfigFile(digester, path); } getServletContext().setAttribute( Globals.MODULE_KEY + config.getPrefix(), config); // Force creation and registration of DynaActionFormClass instances // for all dynamic form beans we wil be using FormBeanConfig fbs[] = config.findFormBeanConfigs(); for (int i = 0; i < fbs.length; i++) { if (fbs[i].getDynamic()) { fbs[i].getDynaActionFormClass(); } } return config; }代码中,ModuleConfig对象是经过ModuleConfig config = factoryObject.createModuleConfig(prefix);建立的,继续跟进
/** * A factory for creating {@link ModuleConfig} instances. * * @see ModuleConfig * @see ModuleConfigFactory * * @version $Rev: 54929 $ $Date: 2004-10-16 17:38:42 +0100 (Sat, 16 Oct 2004) $ */ public class DefaultModuleConfigFactory extends ModuleConfigFactory implements Serializable{ // --------------------------------------------------------- Public Methods /** * Create and return a newly instansiated {@link ModuleConfig}. * This method must be implemented by concrete subclasses. * * @param prefix Module prefix for Configuration */ public ModuleConfig createModuleConfig(String prefix) { return new ModuleConfigImpl(prefix); } }
/** * Construct an ModuleConfigImpl object according to the specified * parameter values. * * @param prefix Context-relative URI prefix for this module */ public ModuleConfigImpl(String prefix) { super(); this.prefix = prefix; this.actionConfigs = new HashMap(); this.actionConfigList = new ArrayList(); this.actionFormBeanClass = "org.apache.struts.action.ActionFormBean"; this.actionMappingClass = "org.apache.struts.action.ActionMapping"; this.actionForwardClass = "org.apache.struts.action.ActionForward"; this.configured = false; this.controllerConfig = null; this.dataSources = new HashMap(); this.exceptions = new HashMap(); this.formBeans = new HashMap(); this.forwards = new HashMap(); this.messageResources = new HashMap(); this.plugIns = new ArrayList(); }清晰明了,struts为每个配置文件建立了一个ModuleConfigImpl对象,经过该对象的prefix属性区分不一样的配置文件。
额外的细节,initModuleConfig中还作了两件事,第一,配置信息使用common-digester读取配置信息并放入ModuleConfigImpl对象中(能够阅读Digester digester = initConfigDigester();和this.parseModuleConfigFile(digester, path);这两个方法);第二,struts将加载好的ModuleConfigImpl放入了ServletContext中(getServletContext().setAttribute(Globals.MODULE_KEY + config.getPrefix(),config);)。 ide
/** * <P>Ask the specified <code>Action</code> instance to handle this * request. Return the <code>ActionForward</code> instance (if any) * returned by the called <code>Action</code> for further processing. * </P> * * @param request The servlet request we are processing * @param response The servlet response we are creating * @param action The Action instance to be used * @param form The ActionForm instance to pass to this Action * @param mapping The ActionMapping instance to pass to this Action * * @exception IOException if an input/output error occurs * @exception ServletException if a servlet exception occurs */ protected ActionForward processActionPerform(HttpServletRequest request, HttpServletResponse response, Action action, ActionForm form, ActionMapping mapping) throws IOException, ServletException { try { return (action.execute(mapping, form, request, response)); } catch (Exception e) { return (processException(request, response, e, form, mapping)); } }
/** * <p>Ask our exception handler to handle the exception. Return the * <code>ActionForward</code> instance (if any) returned by the * called <code>ExceptionHandler</code>.</p> * * @param request The servlet request we are processing * @param response The servlet response we are processing * @param exception The exception being handled * @param form The ActionForm we are processing * @param mapping The ActionMapping we are using * * @exception IOException if an input/output error occurs * @exception ServletException if a servlet exception occurs */ protected ActionForward processException(HttpServletRequest request, HttpServletResponse response, Exception exception, ActionForm form, ActionMapping mapping) throws IOException, ServletException { // Is there a defined handler for this exception? ExceptionConfig config = mapping.findException(exception.getClass()); if (config == null) { log.warn(getInternal().getMessage("unhandledException", exception.getClass())); if (exception instanceof IOException) { throw (IOException) exception; } else if (exception instanceof ServletException) { throw (ServletException) exception; } else { throw new ServletException(exception); } } // Use the configured exception handling try { ExceptionHandler handler = (ExceptionHandler) RequestUtils.applicationInstance(config.getHandler()); return (handler.execute(exception, config, mapping, form, request, response)); } catch (Exception e) { throw new ServletException(e); } }
processException干了两件事,首先获取异常配置信息(ExceptionConfig config = mapping.findException(exception.getClass());),若获取不到且不是IO或Servlet的异常,抛出ServletException让容器处理;若读取到异常配置信息,则根据配置信息尝试用ExceptionHandler处理异常。 oop
获取异常配置信息的流程中,还有一些东西,mapping是struts配置文件中某个action对应的配置信息 this
/** * <p>Find and return the <code>ExceptionConfig</code> instance defining * how <code>Exceptions</code> of the specified type should be handled. * This is performed by checking local and then global configurations for * the specified exception's class, and then looking up the superclass chain * (again checking local and then global configurations). If no handler * configuration can be found, return <code>null</code>.</p> * * <p>Introduced in <code>ActionMapping</code> in Struts 1.1, but pushed * up to <code>ActionConfig</code> in Struts 1.2.0.</p> * * @param type Exception class for which to find a handler * @since Struts 1.2.0 */ public ExceptionConfig findException(Class type) { // Check through the entire superclass hierarchy as needed ExceptionConfig config = null; while (true) { // Check for a locally defined handler String name = type.getName(); config = findExceptionConfig(name); if (config != null) { return (config); } // Check for a globally defined handler config = getModuleConfig().findExceptionConfig(name); if (config != null) { return (config); } // Loop again for our superclass (if any) type = type.getSuperclass(); if (type == null) { break; } } return (null); // No handler has been configured }首先他会尝试根据异常Class信息,读取当前action的异常处理配置,若没有读取到,则经过getModuleConfig()获取当前action所在struts配置文件的信息(config = getModuleConfig().findExceptionConfig(name);),从而尝试获得全局异常(global-exceptions)配置。
1. struts对没一个struts配置文件都生成一个ModuleConfigImpl对象存放其信息;每个struts配置文件汇总的action配置都会生成一个ActionConfig对象存放其配置信息; spa
2. ActionServlet能够捕获到Action层抛出的异常信息,可是真正的处理是依靠RequestProcesser完成的(processException方法); debug
3. struts的异常配置首先读取当前action的,而后是struts配置中全局的; code
4. struts的异常能够向上查询,好比struts会一次查找IllegalArgumentException-》RuntimeException-》Exception-》Throwable。