Java深入 - Spring 異常處理HandlerExceptionResolver

Spring的異常統一處理非常簡單,首先我們需要看一下Spring中定義的HandlerExceptionResolver接口:

/** 
 * Interface to be implemented by objects than can resolve exceptions thrown 
 * during handler mapping or execution, in the typical case to error views. 
 * Implementors are typically registered as beans in the application context. 
 * 
 * <p>Error views are analogous to the error page JSPs, but can be used with 
 * any kind of exception including any checked exception, with potentially 
 * fine-granular mappings for specific handlers. 
 * 
 * @author Juergen Hoeller 
 * @since 22.11.2003 
 */  
public interface HandlerExceptionResolver {  

    /** 
     * Try to resolve the given exception that got thrown during on handler execution, 
     * returning a ModelAndView that represents a specific error page if appropriate. 
     * <p>The returned ModelAndView may be {@linkplain ModelAndView#isEmpty() empty} 
     * to indicate that the exception has been resolved successfully but that no view 
     * should be rendered, for instance by setting a status code. 
     * @param request current HTTP request 
     * @param response current HTTP response 
     * @param handler the executed handler, or <code>null</code> if none chosen at the 
     * time of the exception (for example, if multipart resolution failed) 
     * @param ex the exception that got thrown during handler execution 
     * @return a corresponding ModelAndView to forward to, 
     * or <code>null</code> for default processing 
     */  
    ModelAndView resolveException(  
            HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex);  

}  

他定義了一個resolveException方法,我們如果要處理異常的話,需要實現這個接口類,並且實現resolveException方法,在resolveException方法中處理自己的異常邏輯。
例如我設計一個自定義的異常處理類:
/** 
 * 自定義一個異常捕獲處理類 
 * @author zhuli 
 * @date 2014-9-3 
 */  
public class MyExceptionResolver implements HandlerExceptionResolver {  

    private static final Logger logger = LoggerFactory.getLogger(MyExceptionResolver.class);  

    @Override  
    public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {  

        //可以自由處理各種異常邏輯  
        if (ex instanceof org.springframework.web.HttpRequestMethodNotSupportedException) {  
            logger.warn(Logger.ACTION.DEFAULT, "Http Method Error");  
        }  
        return null;  
    }  

}  

然後需要將我們的我們自定義的MyExceptionResolver類注入到bean中

<bean id="MyExceptionResolver" class="com.tiantian.xxx.web.handler.MyExceptionResolver"/> 

具體Spring是怎麼調用的?我們可以先看下Spring中的doDispatch方法中,有這麼一段代碼:

catch (ModelAndViewDefiningException ex) {  
    logger.debug("ModelAndViewDefiningException encountered", ex);  
    mv = ex.getModelAndView();  
}  
catch (Exception ex) {  
    Object handler = (mappedHandler != null ? mappedHandler.getHandler() : null);  
    mv = processHandlerException(processedRequest, response, handler, ex);  
    errorView = (mv != null);  
}  

其中processHandlerException方法就是來捕獲異常處理的,那麼繼續看processHandlerException這個方法:

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

    // Check registered HandlerExceptionResolvers...  
    ModelAndView exMv = null;  
    for (HandlerExceptionResolver handlerExceptionResolver : this.handlerExceptionResolvers) {  
        exMv = handlerExceptionResolver.resolveException(request, response, handler, ex);  
        if (exMv != null) {  
            break;  
        }  
    }  
    if (exMv != null) {  
        if (exMv.isEmpty()) {  
            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;  
}  

這個方法中的handlerExceptionResolver.resolveException就是用來捕獲異常的,並且Spring允許多個自定義的異常類實現。
可以看this.handlerExceptionResolvers方法,跟蹤進去

private void initHandlerExceptionResolvers(ApplicationContext context) {  
        this.handlerExceptionResolvers = null;  

        if (this.detectAllHandlerExceptionResolvers) {  
            // Find all HandlerExceptionResolvers in the ApplicationContext, including ancestor contexts.  
            Map<String, HandlerExceptionResolver> matchingBeans = BeanFactoryUtils  
                    .beansOfTypeIncludingAncestors(context, HandlerExceptionResolver.class, true, false);  
            if (!matchingBeans.isEmpty()) {  
                this.handlerExceptionResolvers = new ArrayList<HandlerExceptionResolver>(matchingBeans.values());  
                // We keep HandlerExceptionResolvers in sorted order.  
                OrderComparator.sort(this.handlerExceptionResolvers);  
            }  
        }  
        else {  
            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  
        // default HandlerExceptionResolvers if no other resolvers are found.  
        if (this.handlerExceptionResolvers == null) {  
            this.handlerExceptionResolvers = getDefaultStrategies(context, HandlerExceptionResolver.class);  
            if (logger.isDebugEnabled()) {  
                logger.debug("No HandlerExceptionResolvers found in servlet '" + getServletName() + "': using default");  
            }  
        }  
    }

可以清洗看到這個方法是將handlerExceptionResolvers進行了初始化,並將自定義的異常處理類(可以多個)寫入this.handlerExceptionResolvers

發佈了71 篇原創文章 · 獲贊 2 · 訪問量 6萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章