- 浏览: 50368 次
- 性别:
- 来自: 南京
文章分类
最新评论
前序:本文的意义在于了解 tomcat处理异常
请求访问后台时,并不是一帆风顺的。有时可能模型驱动绑定时发生错误,或者执行目标方法时发生异常。springmvc是如何处理这些不可知的异常的呢?
根据<spring源码学习系列3.2-handlerAdapter执行>最后一个方法源码的分析,可以简单了解springmvc是如何处理这些异常的
MultiActionController#handleRequestInternal
如果抛出的异常为NoSuchRequestHandlingMethodException,则返回404错误
MultiActionController#invokeNamedMethod
MultiActionController#handleException
从这里可以看到springmvc对异常的处理一是自定义处理方法,二是继续抛出异常
---------------------------------------------------springmvc处理异常
1.自定义处理方法
MultiActionController#getExceptionHandler
在初始化controller时,会注册exceptionHandlerMap。自定义的controller中符合格式的方法,会当做异常处理方法注册
异常处理方法条件:
a. 第一个参数为HttpServletRequest,第二个参数为HttpServletResponse,第三个参数为Throwable的子类
b. 返回类型ModelAndView Map String 或 void
---------------------------------------------------tomcat处理异常
2.抛出异常,让tomcat处理
用户(开发者)可以在程序中(web.xml)设置错误码(response.setErrorCode),将抛出的异常定位到对ui更友好的界面,如:
应用启动时解析web.xml,将错误码或异常对应的页面设置到errorPage,并设置到Context应用的属性。后续程序发生异常在StandardHostValve处理过程中抛出异常
整个请求处理流程中,会在Pipeline中包含一系列的Valve,其中有2个value StandardHostValve和ErrorReportValve
StandardHostValve就是调用web.xml中配置的errorPage,返回给浏览器
StandardHostValve#throwable
若没有配置则ErrorReportValve中硬编码生成异常页面,返回给浏览器
StandardHostValve源码
http://grepcode.com/file/repo1.maven.org/maven2/org.apache.tomcat/tomcat-catalina/7.0.0/org/apache/catalina/core/StandardHostValve.java
ErrorReportValve源码:
http://grepcode.com/file/repo1.maven.org/maven2/org.apache.tomcat/tomcat-catalina/7.0.0/org/apache/catalina/valves/ErrorReportValve.java#ErrorReportValve
参考:
你的错误页面。不,是你的错误页面
http://www.10tiao.com/html/142/201610/2650859268/1.html
Tomcat 的 ErrorPage 实现原理分析
http://www.cnblogs.com/softidea/p/5981766.html
Tomcat的错误异常状态返回报告页 Error Report Valve(Valve源码分析之八
http://www.10tiao.com/html/308/201702/2650076436/1.html
【Tomcat源码学习】-3.应用管理
http://www.cnblogs.com/hframe/p/5326352.html
请求访问后台时,并不是一帆风顺的。有时可能模型驱动绑定时发生错误,或者执行目标方法时发生异常。springmvc是如何处理这些不可知的异常的呢?
根据<spring源码学习系列3.2-handlerAdapter执行>最后一个方法源码的分析,可以简单了解springmvc是如何处理这些异常的
MultiActionController#handleRequestInternal
@Override protected ModelAndView handleRequestInternal(HttpServletRequest request, HttpServletResponse response) throws Exception { try { String methodName = this.methodNameResolver.getHandlerMethodName(request); return invokeNamedMethod(methodName, request, response); } catch (NoSuchRequestHandlingMethodException ex) { return handleNoSuchRequestHandlingMethod(ex, request, response); } }
如果抛出的异常为NoSuchRequestHandlingMethodException,则返回404错误
MultiActionController#invokeNamedMethod
protected final ModelAndView invokeNamedMethod( String methodName, HttpServletRequest request, HttpServletResponse response) throws Exception { //获取方法执行体,handlerMethodMap在构造函数里面初始化 Method method = this.handlerMethodMap.get(methodName); if (method == null) { throw new NoSuchRequestHandlingMethodException(methodName, getClass()); } try { ...... } catch (InvocationTargetException ex) { // The handler method threw an exception. return handleException(request, response, ex.getTargetException()); } catch (Exception ex) { // The binding process threw an exception. return handleException(request, response, ex); } }
MultiActionController#handleException
private ModelAndView handleException(HttpServletRequest request, HttpServletResponse response, Throwable ex) throws Exception { Method handler = getExceptionHandler(ex); if (handler != null) { if (logger.isDebugEnabled()) { logger.debug("Invoking exception handler [" + handler + "] for exception: " + ex); } try { Object returnValue = handler.invoke(this.delegate, request, response, ex); return massageReturnValueIfNecessary(returnValue); } catch (InvocationTargetException ex2) { logger.error("Original exception overridden by exception handling failure", ex); ReflectionUtils.rethrowException(ex2.getTargetException()); } catch (Exception ex2) { logger.error("Failed to invoke exception handler method", ex2); } } else { // If we get here, there was no custom handler or we couldn't invoke it. ReflectionUtils.rethrowException(ex); } throw new IllegalStateException("Should never get here"); }
从这里可以看到springmvc对异常的处理一是自定义处理方法,二是继续抛出异常
---------------------------------------------------springmvc处理异常
1.自定义处理方法
MultiActionController#getExceptionHandler
protected Method getExceptionHandler(Throwable exception) { Class exceptionClass = exception.getClass(); if (logger.isDebugEnabled()) { logger.debug("Trying to find handler for exception class [" + exceptionClass.getName() + "]"); } Method handler = this.exceptionHandlerMap.get(exceptionClass); while (handler == null && !exceptionClass.equals(Throwable.class)) { if (logger.isDebugEnabled()) { logger.debug("Trying to find handler for exception superclass [" + exceptionClass.getName() + "]"); } exceptionClass = exceptionClass.getSuperclass(); handler = this.exceptionHandlerMap.get(exceptionClass); } return handler; }
在初始化controller时,会注册exceptionHandlerMap。自定义的controller中符合格式的方法,会当做异常处理方法注册
private boolean isExceptionHandlerMethod(Method method) { return (isHandlerMethod(method) && method.getParameterTypes().length == 3 && Throwable.class.isAssignableFrom(method.getParameterTypes()[2])); }
异常处理方法条件:
a. 第一个参数为HttpServletRequest,第二个参数为HttpServletResponse,第三个参数为Throwable的子类
b. 返回类型ModelAndView Map String 或 void
---------------------------------------------------tomcat处理异常
2.抛出异常,让tomcat处理
用户(开发者)可以在程序中(web.xml)设置错误码(response.setErrorCode),将抛出的异常定位到对ui更友好的界面,如:
<error-page> <error-code>404</error-code> <location>/errorpages/404.jsp</location> </error-page> <error-page> <exception-type>Java.lang.Exception</exception-type> <location>/errorpages/exception.jsp</location> </error-page>
应用启动时解析web.xml,将错误码或异常对应的页面设置到errorPage,并设置到Context应用的属性。后续程序发生异常在StandardHostValve处理过程中抛出异常
整个请求处理流程中,会在Pipeline中包含一系列的Valve,其中有2个value StandardHostValve和ErrorReportValve
StandardHostValve就是调用web.xml中配置的errorPage,返回给浏览器
StandardHostValve#throwable
protected void throwable(Request request, Response response, Throwable throwable) { ......... ErrorPage errorPage = findErrorPage(context, throwable); if ((errorPage == null) && (realError != throwable)) { errorPage = findErrorPage(context, realError); } if (errorPage != null) { response.setAppCommitted(false); request.setAttribute (ApplicationFilterFactory.DISPATCHER_REQUEST_PATH_ATTR, errorPage.getLocation()); request.setAttribute(ApplicationFilterFactory.DISPATCHER_TYPE_ATTR, DispatcherType.ERROR); request.setAttribute (Globals.STATUS_CODE_ATTR, new Integer(HttpServletResponse.SC_INTERNAL_SERVER_ERROR)); request.setAttribute(Globals.ERROR_MESSAGE_ATTR, throwable.getMessage()); request.setAttribute(Globals.EXCEPTION_ATTR, realError); Wrapper wrapper = request.getWrapper(); if (wrapper != null) request.setAttribute(Globals.SERVLET_NAME_ATTR, wrapper.getName()); request.setAttribute(Globals.EXCEPTION_PAGE_ATTR, request.getRequestURI()); request.setAttribute(Globals.EXCEPTION_TYPE_ATTR, realError.getClass()); if (custom(request, response, errorPage)) { try { response.flushBuffer(); } catch (IOException e) { container.getLogger().warn("Exception Processing " + errorPage, e); } } } ....... }
若没有配置则ErrorReportValve中硬编码生成异常页面,返回给浏览器
StandardHostValve源码
http://grepcode.com/file/repo1.maven.org/maven2/org.apache.tomcat/tomcat-catalina/7.0.0/org/apache/catalina/core/StandardHostValve.java
ErrorReportValve源码:
http://grepcode.com/file/repo1.maven.org/maven2/org.apache.tomcat/tomcat-catalina/7.0.0/org/apache/catalina/valves/ErrorReportValve.java#ErrorReportValve
参考:
你的错误页面。不,是你的错误页面
http://www.10tiao.com/html/142/201610/2650859268/1.html
Tomcat 的 ErrorPage 实现原理分析
http://www.cnblogs.com/softidea/p/5981766.html
Tomcat的错误异常状态返回报告页 Error Report Valve(Valve源码分析之八
http://www.10tiao.com/html/308/201702/2650076436/1.html
【Tomcat源码学习】-3.应用管理
http://www.cnblogs.com/hframe/p/5326352.html
发表评论
-
spring疑难解惑-循环依赖的解决
2020-06-17 23:27 539AbstractAutowireCapableBeanFact ... -
spring容器
2019-07-14 08:47 305private final ServletContainer ... -
spring容器
2019-07-13 23:35 0spring容器与springmvc容器 73 ... -
spring源码学习系列2.6-spring ioc原理-codes
2019-03-05 22:56 487web.xml <listener> < ... -
spring源码学习系列3.4-spring mvc原理-codes
2019-01-21 22:46 296本篇章从核心类角度解读springmvc的原理 web.xm ... -
spring源码学习系列4.2-spring aop原理-codes
2018-12-04 22:29 561jdk: Proxy InvocationHandler ... -
spring源码学习系列4.1-spring实现对ibatis的事务管理
2018-09-17 15:44 578事务由spring管理,可以理解为由spring管理数据库连接 ... -
spring源码学习系列4-3种常用的自动代理创建器
2018-09-02 15:48 5703种自动代理器是 AnnotationAwareAspectJ ... -
spring源码学习系列1.2-spring事务代理深入分析2
2018-05-27 19:46 451提示: BeanPostProcessor AopUtils ... -
spring源码学习系列2.5-ApplicationContext初始化-设计模式
2018-05-08 15:17 519ApplicationContext容器的初始化可以通过模板方 ... -
spring源码学习系列3.3-DispatcherServlet初始化-设计模式
2018-05-07 11:12 622springmvc的核心是DispatcherServlet ... -
封装spring-security
2018-01-23 19:33 518github地址: https://github.com/ne ... -
eclipse导入spring源码
2018-05-12 07:20 980spring在git上的项目时gradle管理jar包的,所以 ... -
spring源码学习系列3.2.2-How to bind String to Date
2017-07-17 12:40 597springmvc开发中,经常需将界面日期数据(String) ... -
spring源码学习系列3.2.1-command对象的绑定
2017-05-28 12:00 981在<spring源码学习系列3.2-handlerAda ... -
spring源码学习系列3.2-handlerAdapter执行
2017-05-28 12:01 409DispatcherServlet#doDispatch中调用 ... -
spring源码学习系列3.1-handlerMapping初始化
2017-05-28 11:56 701SimpleUrlHandlerMapping的继承体系 or ... -
spring源码学习系列2.4-finishRefresh会做什么
2017-05-06 16:36 578spring容器初始化完成后,调用finishRresh 该 ... -
spring源码学习系列3-springmvc原理
2017-05-28 11:56 456问题: springmvc是如何控 ... -
spring源码学习系列2-容器初始化入口-refresh
2017-04-23 21:33 477context=XmlWebApplicationContex ...
相关推荐
在Linux环境下部署Oracle 11g数据库时,经常会遇到对特定依赖包的需求,"compat-libstdc++-33-3.2.3-72.el7.x86_64.zip"就是这样一个关键组件。这个压缩包包含了适用于x86_64架构的Linux系统(如CentOS 7)的兼容性...
"compat-libstdc++-33-3.2.3-72.el7.x86_64.rar"与"compat-libstdc++-33-3.2.3-69.el6.x86_64.rpm"这两个文件,是专门为解决旧版GCC标准C++库的兼容性问题而设计的。它们为Red Hat 6和7两个版本提供了支持,使得旧...
compat-gcc-32-3.2.3-72.el7.src.rpm linux上安装oracle所需依赖包
compat-libstdc++-33-3.2.3-72.el7.x86_64.rpm
compat-libstdc++-33-3.2.3-61.i386.rpm;Linux系统
compat-libstdc++-33-3.2.3-71.el7.x86_64
标题中的"compat-libstdc++-33-3.2.3-69.el6.x86_64"指的是一个Linux系统中的软件包,它主要用于兼容性支持。这个包是为了解决不同版本的GNU标准C++库(libstdc++)之间的不兼容问题,特别是针对旧版的应用程序或者...
标题中的"compat-libstdc++-33-3.2.3-72.el7.i686.zip"是一个特定的软件包,它包含了适用于32位系统(i686架构)的“compat-libstdc++-33”库。这个库是一个兼容性版本的GNU标准C++库,主要目的是为了支持某些旧版或...
`compat-libstdc++-33-3.2.3-69.el6.x86_64`这个特定版本对应的是GCC(GNU Compiler Collection)3.3系列的标准C++库。GCC 3.3是在2003年发布的,而`el6`代表的是RHEL/CentOS 6系列,这些系统可能默认预装了更早版本...
compat-libstdc++-33-3.2.3-72.el7.i686.rpm
"compat-libstdc++-33-3.2.3-72.el7.x86_64.rpm"这个文件就是这样一个关键依赖,它是为Oracle数据库提供兼容性支持的库。 `compat-libstdc++-33`是一个针对旧版Oracle数据库的兼容性库,特别是对那些需要GCC 3.2.3...
linux下安装oracle安装需要的compat-libstdc++-33-3.2.3-72.el7.x86_64.rpm和ksh-20120801-33.el6.i686.rpm
安装amazon hdx 8.9 的android7.1所需的apollo_twrp-3.2.3-1.img
GDAL-3.2.3-cp38-cp38-win_amd64
linux compat-libstdc++-33-3.2.3-72.eI7.x86_64.rpm.