struts1.* 異常處理機制

幾個重要類的說明

ActionServlet  struts的核心類,用於初始化struts配置文件,處理髮送到action的請求;
ModuleConfig  struts配置文件信息加載的接口,ModuleConfigImpl是接口的默認實現,能夠完成基於配置信息的信息讀、取操做。每一個struts模塊文件對應一個實例。
ActionConfig  用於存儲action配置信息的實體,配置文件中每個action對應一個ActionConfig。該類包含該action所在struts配置文件對應的ModuleConfig;它的子類ActionMapping很眼熟吧,action層方法的參數中都有它。
RequestProcessor  請求處理實體類負責處理Action攔截到的請求處理。


初始化加載

struts的啓動加載類是ActionServlet,文如其名它是Servlet的擴展,所以初始化在init方法中執行。
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



異常處理

action層拋出異常後,被ActionServlet捕獲,processException完成了異常信息的處理



/**
     * <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)配置。
若是當前Class沒有獲取到,該方法會查找當前異常類的父類,並查看action和struts配置的異常處理配置中是否有相應配置。

知識點總結

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。

相關文章
相關標籤/搜索