环境:Springboot3.0.5
创新互联建站-专业网站定制、快速模板网站建设、高性价比榆社网站开发、企业建站全套包干低至880元,成熟完善的模板库,直接使用。一站式榆社网站制作公司更省心,省钱,快速模板网站建设找我们,业务覆盖榆社地区。费用合理售后完善,十载实体公司更值得信赖。
如果在请求映射期间发生异常或从请求处理程序(例如@Controller)抛出异常,DispatcherServlet将委托给HandlerExceptionResolver。
下表列出了可用的HandlerExceptionResolver实现。
HandlerExceptionResolver 实现类:
HandlerExceptionResolver |
描述 |
SimpleMappingExceptionResolver |
异常类名和错误视图名之间的映射。用于在浏览器应用程序中渲染错误页面。 |
DefaultHandlerExceptionResolver |
解析Spring MVC引发的异常,并将其映射为HTTP状态码。 |
ResponseStatusExceptionResolver |
使用@ResponseStatus注解解析异常,并根据注解中的值将异常映射为HTTP状态码。 |
ExceptionHandlerExceptionResolver |
通过在@Controller或@ControllerAdvice类中调用由@ExceptionHandler注释的方法来解决异常。 |
我们可以声明多个HandlerExceptionResolver
HandlerExceptionResolver的约定规定它可以返回:
SpringMVC请求入口通过DispatcherServlet执行大致核心流程如下:
这里以Controller接口为例,HandlerAdapter对象为RequestMappingHandlerAdapter。
public class DispatcherServlet extends FrameworkServlet {
protected void doDispatch(...) throws Exception {
HandlerExecutionChain mappedHandler = null;
try {
Exception dispatchException = null;
// 根据请求确定Handler对象(遍历所有的HandlerMapping)
mappedHandler = getHandler(processedRequest);
// 根据上一步确定的Handler对象,确定HandlerAdapter对象
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
// 真正执行目标方法的调用
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
} catch (Exception ex) {
dispatchException = ex;
} catch (Throwable err) {
dispatchException = new ServletException("Handler dispatch failed: " + err, err);
}
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
}
}
public class RequestMappingHandlerAdapter {
protected ModelAndView handleInternal(...) throws Exception {
ModelAndView mav;
mav = invokeHandlerMethod(request, response, handlerMethod);
}
protected ModelAndView invokeHandlerMethod(...) throws Exception {
// ...
ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod);
// ... 对ServletInvocableHandlerMethod进行配置
invocableMethod.invokeAndHandle(webRequest, mavContainer);
return getModelAndView(mavContainer, modelFactory, webRequest);
}
}
ServletInvocableHandlerMethod执行参数解析目标Controller方法调用及返回值的处理。
public class ServletInvocableHandlerMethod extends InvocableHandlerMethod {
public void invokeAndHandle(...) throws Exception {
// 该方法中会进行请求参数的解析及目标方法的调用
Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);
// ...
try {
// 处理返回值
this.returnValueHandlers.handleReturnValue(returnValue, getReturnValueType(returnValue), mavContainer, webRequest);
} catch (Exception ex) {
throw ex;
}
}
}
通过上面的源码分析,在调用过程中如果发生了异常会将异常直接抛出,在DispatcherServlet中会进行异常的处理。
接着上面的源码分析,当发生异常后最终会在DispatcherServlet#processDispatchResult方法中进行处理。
public class DispatcherServlet extends FrameworkServlet {
/*
* 默认情况下有如下2个异常解析器
* 1. DefaultErrorAttributes
* 2. ExceptionHandlerExceptionResolver
*/
private List handlerExceptionResolvers;
private void processDispatchResult(...) {
if (exception != null) {
Object handler = (mappedHandler != null ? mappedHandler.getHandler() : null);
// 处理异常
mv = processHandlerException(request, response, handler, exception);
}
}
protected ModelAndView processHandlerException(...) throws Exception {
ModelAndView exMv = null;
if (this.handlerExceptionResolvers != null) {
// 遍历所有的异常解析器
for (HandlerExceptionResolver resolver : this.handlerExceptionResolvers) {
// 解析异常,核心的解析器是ExceptionHandlerExceptionResolver
exMv = resolver.resolveException(request, response, handler, ex);
}
}
// ...
}
}
ExceptionHandlerExceptionResolver类继承自AbstractHandlerMethodExceptionResolver该类又继承自AbstractHandlerExceptionResolver。
// 调用父类(AbstractHandlerExceptionResolver)方法
public abstract class AbstractHandlerExceptionResolver implements HandlerExceptionResolver, Ordered {
public ModelAndView resolveException(...) {
// doResolveException该方法在子类AbstractHandlerMethodExceptionResolver中重写
ModelAndView result = doResolveException(request, response, handler, ex);
}
}
AbstractHandlerMethodExceptionResolver
public abstract class AbstractHandlerMethodExceptionResolver extends AbstractHandlerExceptionResolver {
protected final ModelAndView doResolveException(...) {
HandlerMethod handlerMethod = (handler instanceof HandlerMethod hm ? hm : null);
return doResolveHandlerMethodException(request, response, handlerMethod, ex);
}
}
ExceptionHandlerExceptionResolver
public class ExceptionHandlerExceptionResolver extends AbstractHandlerMethodExceptionResolver implements ApplicationContextAware, InitializingBean {
protected ModelAndView doResolveHandlerMethodException(...) {
// 该方法中会先从当前的Controller中查找是否有@ExceptionHandler注解的方法(如果匹配)
// 如果没有再从全局的异常处理类句柄中查找
ServletInvocableHandlerMethod exceptionHandlerMethod = getExceptionHandlerMethod(handlerMethod, exception);
if (exceptionHandlerMethod == null) {
return null;
}
// 执行异常处理方法的调用
exceptionHandlerMethod.invokeAndHandle(webRequest, mavContainer, arguments);
}
protected ServletInvocableHandlerMethod getExceptionHandlerMethod(...) {
Class> handlerType = null;
if (handlerMethod != null) {
handlerType = handlerMethod.getBeanType();
// 缓存并设置当前执行Class对应的ExceptionHandlerMethodResolver
// ExceptionHandlerMethodResolver构造函数中会解析当前类中的所有方法是否有@ExceptionHandler注解
ExceptionHandlerMethodResolver resolver = this.exceptionHandlerCache.computeIfAbsent(handlerType, ExceptionHandlerMethodResolver::new);
// 解析是否匹配当前发生的异常
Method method = resolver.resolveMethod(exception);
if (method != null) {
return new ServletInvocableHandlerMethod(handlerMethod.getBean(), method, this.applicationContext);
}
}
// 如果上面的执行的Class中没有找到对应处理器,那么就从全局的异常处理中进行查找匹配
// 这里的exceptionHandlerAdviceCache集合在类初始化执行时已经处理完成
for (Map.Entry entry : this.exceptionHandlerAdviceCache.entrySet()) {
ControllerAdviceBean advice = entry.getKey();
if (advice.isApplicableToBeanType(handlerType)) {
ExceptionHandlerMethodResolver resolver = entry.getValue();
Method method = resolver.resolveMethod(exception);
if (method != null) {
return new ServletInvocableHandlerMethod(advice.resolveBean(), method, this.applicationContext);
}
}
}
return null;
}
}
通过上面的源码分析你应该知道了关于SpringMVC中异常处理的原理。
当上面的异常处理机制都没法处理,那么将会调用默认的/error接口。
public class ErrorMvcAutoConfiguration {
@Bean
@ConditionalOnMissingBean(value = ErrorController.class, search = SearchStrategy.CURRENT)
public BasicErrorController basicErrorController(ErrorAttributes errorAttributes, ObjectProvider errorViewResolvers) {
return new BasicErrorController(errorAttributes, this.serverProperties.getError(), errorViewResolvers.orderedStream().toList());
}
}
@Controller
@RequestMapping("${server.error.path:${error.path:/error}}")
public class BasicErrorController extends AbstractErrorController {
}
上面的错误接口/error在容器启动时会自动注册到内嵌的容器中,如:Tomcat。
分享名称:详解SpringBoot接口异常处理机制及源码分析
本文路径:http://www.shufengxianlan.com/qtweb/news2/300552.html
网站建设、网络推广公司-创新互联,是专注品牌与效果的网站制作,网络营销seo公司;服务项目有等
声明:本网站发布的内容(图片、视频和文字)以用户投稿、用户转载内容为主,如果涉及侵权请尽快告知,我们将会在第一时间删除。文章观点不代表本网站立场,如需处理请联系客服。电话:028-86922220;邮箱:631063699@qq.com。内容未经允许不得转载,或转载时需注明来源: 创新互联