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。