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);

//用于加载配其他struts配置文件
moduleConfig = initModuleConfig
                    (prefix, getServletConfig().getInitParameter(name));

从以上代码可以看出,不同的struts配置文件肯定是根据参数进行区分了,其中prefix是web.xml中struts配置信息去掉“config/”之后param-name,下面配置信息中的prefix为page/user

<!-- 用户管理配置文件 -->
		<init-param>
			<param-name>config/page/user</param-name>
			<param-value>
				/WEB-INF/config/struts/module/struts-user.xml
			</param-value>
		</init-param>


如何区分和保存,看下面的代码:

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);)。



异常处理
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处理异常。

获取异常配置信息的流程中,还有一些东西,mapping是struts配置文件中某个action对应的配置信息

/**
     * <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对象存放其配置信息;

2. ActionServlet可以捕获到Action层抛出的异常信息,但是真正的处理是依靠RequestProcesser完成的(processException方法);

3. struts的异常配置首先读取当前action的,然后是struts配置中全局的;

4. struts的异常可以向上查询,比如struts会一次查找IllegalArgumentException-》RuntimeException-》Exception-》Throwable。

转载于:https://my.oschina.net/SEyanlei/blog/157783

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值