Springmvc 异常解析器,自定义异常

原文链接: https://my.oschina.net/u/3195939/blog/834301

只要是项目,就会出现异常代码,没有异常的项目就不是好项目,哈哈哈

Springmvc容器启动后,会刷新容器

/**
     * This implementation calls {@link #initStrategies}.
     */
    @Override
    protected void onRefresh(ApplicationContext context) {
        initStrategies(context);
    }

    /**
     * Initialize the strategy objects that this servlet uses.  加载9个解析器
     *

May be overridden in subclasses in order to initialize further strategy objects.
     */
    protected void initStrategies(ApplicationContext context) {
        initMultipartResolver(context);
        initLocaleResolver(context);
        initThemeResolver(context);
        initHandlerMappings(context);
        initHandlerAdapters(context);
        initHandlerExceptionResolvers(context); //我们要研究的异常解析器
        initRequestToViewNameTranslator(context);
        initViewResolvers(context);
        initFlashMapManager(context);
    }

跟踪代码


    /**
     * Initialize the HandlerExceptionResolver used by this class.
     *

If no bean is defined with the given name in the BeanFactory for this namespace,
     * we default to no exception resolver.
     */
    private void initHandlerExceptionResolvers(ApplicationContext context) {
        this.handlerExceptionResolvers = null;

    //detectAllHandlerExceptionResolvers 默认值为true

        if (this.detectAllHandlerExceptionResolvers) {
            //通过BeanFactoryUtils,加载整个web容器内所有,实现HandlerExceptionResolver接口的对象
            Map matchingBeans = BeanFactoryUtils
                    .beansOfTypeIncludingAncestors(context, HandlerExceptionResolver.class, true, false);
            if (!matchingBeans.isEmpty()) {
                this.handlerExceptionResolvers = new ArrayList(matchingBeans.values());
                // 对接口实现类进行排序
                OrderComparator.sort(this.handlerExceptionResolvers);
            }
        }
        else {

        //detectAllHandlerExceptionResolvers =false ,只加载HandlerExceptionResolver本身
            try {
                HandlerExceptionResolver her =
                        context.getBean(HANDLER_EXCEPTION_RESOLVER_BEAN_NAME, HandlerExceptionResolver.class);
                this.handlerExceptionResolvers = Collections.singletonList(her);
            }
            catch (NoSuchBeanDefinitionException ex) {
                // Ignore, no HandlerExceptionResolver is fine too.
            }
        }

        // Ensure we have at least some HandlerExceptionResolvers, by registering
        // 如果没有发现 HandlerExceptionResolvers 加载DispatcherServlet.properties中对应的默认解析器
        if (this.handlerExceptionResolvers == null) {
            this.handlerExceptionResolvers = getDefaultStrategies(context, HandlerExceptionResolver.class);
            if (logger.isDebugEnabled()) {
                logger.debug("No HandlerExceptionResolvers found in servlet '" + getServletName() + "': using default");
            }
        }
    }

到此异常解析器加载完毕,我们知道 DispatcherServlet类是一个HttpServletBean的子类,就是一个servlet

所有的请求都是会进入到servlet的doService();而DispatcherServlet中的核心代码如下

try {
            doDispatch(request, response);//所有的处理到会到此方法中
        }
        finally {
            if (!WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
                // Restore the original attribute snapshot, in case of an include.
                if (attributesSnapshot != null) {
                    restoreAttributesAfterInclude(request, attributesSnapshot);
                }
            }
        }

 

 

doDispatch(HttpServletRequest request, HttpServletResponse response)中的异常捕获如下

catch (Exception ex) {
                dispatchException = ex;
            }
          (1)  processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
        }
        catch (Exception ex) {
          (2)  triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
        }
        catch (Error err) {
           (3) triggerAfterCompletionWithError(processedRequest, response, mappedHandler, err);
        }

1处的异常会进入到 processDispatchResult此方法中 

  1. // 这里catch住controller抛出的异常,使用持有的ExceptionResolver处理,当没有配置自己的处理器时,程序会将异常继续往上抛出,最终交给我们的容器处理   

 

if (exception != null) {

//判断异常是否属于ModelAndViewDefiningException是ServletException的子类
            if (exception instanceof ModelAndViewDefiningException) {
                logger.debug("ModelAndViewDefiningException encountered", exception);
                mv = ((ModelAndViewDefiningException) exception).getModelAndView();
            }

//不是servlet异常会进入到下面的方法
            else {
                Object handler = (mappedHandler != null ? mappedHandler.getHandler() : null);
                mv = processHandlerException(request, response, handler, exception);
                errorView = (mv != null);
            }
        }

//真正异常处理方法

protected ModelAndView processHandlerException(HttpServletRequest request, HttpServletResponse response,
            Object handler, Exception ex) throws Exception {

        // 循环一开始加载的所有异常解析器
        ModelAndView exMv = null;
        for (HandlerExceptionResolver handlerExceptionResolver : this.handlerExceptionResolvers) {

            //找到合适的解析器,然后返回ModelAndView 
            exMv = handlerExceptionResolver.resolveException(request, response, handler, ex);
            if (exMv != null) {

//找到第一个后跳出循环
                break;
            }
        }
        if (exMv != null) {

//视图和数据模型为空,返回null
            if (exMv.isEmpty()) {
                request.setAttribute(EXCEPTION_ATTRIBUTE, ex);//在request 设置DispatcherServlet.EXCEPTION,内容直接将 Exception ex返回到前台
                return null;
            }
            // We might still need view name translation for a plain error model...
            if (!exMv.hasView()) {
                exMv.setViewName(getDefaultViewName(request));
            }
            if (logger.isDebugEnabled()) {
                logger.debug("Handler execution resulted in exception - forwarding to resolved error view: " + exMv, ex);
            }
            WebUtils.exposeErrorRequestAttributes(request, ex, getServletName());
            return exMv;
        }

        throw ex; @throws Exception if no error ModelAndView found
    }

如果我们在项目中要自定义异常

Spring mvc为我们提供了两种异常处理方式

1.直接实现HandlerExceptionResolver异常解析器的接口,重写

ModelAndView resolveException(
            HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex);

方法,然后实现类用xml,方式注入Spring bean容器中,上面的异常代码解析过程中,自定义的异常解析器会被加载,使用

2.采用注解的方式实现一个专门用于处理异常的Controller—— @ExceptionHandler。

    @ExceptionHandler({MyTestException.class})  

在日志输出异常的时候,一定要注意日志的输出级别 ERROR,INFO ,DEBUG 等

 

 

 

 

 

 

 

 

 

 

转载于:https://my.oschina.net/u/3195939/blog/834301

你可能感兴趣的:(Springmvc 异常解析器,自定义异常)