SpringMVC核心功能异常处理机制原理详解

概述

如果在请求映射期间发生异常或从请求处理程序(例如@Controller)抛出异常,DispatcherServlet将委托给HandlerExceptionResolver

创新互联公司长期为上千家客户提供的网站建设服务,团队从业经验10年,关注不同地域、不同群体,并针对不同对象提供差异化的产品和服务;打造开放共赢平台,与合作伙伴共同营造健康的互联网生态环境。为顺庆企业提供专业的网站设计制作、成都网站设计顺庆网站改版等技术服务。拥有十年丰富建站经验和众多成功案例,为您定制开发。

下表列出了可用的HandlerExceptionResolver实现:

HandlerExceptionResolver

描述

SimpleMappingExceptionResolver

异常类名和错误视图名之间的映射。用于在浏览器应用程序中渲染错误页面。

DefaultHandlerExceptionResolver

解析Spring MVC引发的异常,并将其映射为HTTP状态码。另见可选的ResponseEntityExceptionHandler和REST API异常。

ResponseStatusExceptionResolver

使用@ResponseStatus注解解析异常,并根据注解中的值将异常映射为HTTP状态码。

ExceptionHandlerExceptionResolver

通过在@Controller或@ControllerAdvice类中调用@ExceptionHandler方法来解决异常。

异常解析器链

你可以在Spring配置中声明多个HandlerExceptionResolver

HandlerExceptionResolver的约定规定它可以返回:

  • 指向错误视图的ModelAndView
  • 如果异常是在解析器中处理的,则返回空的ModelAndView
  • 如果异常仍然未解决,则为null,以便后续的解析器尝试,如果异常在最后仍然存在,则允许它向上冒泡到Servlet容器。

MVC配置自动为默认的Spring MVC异常、@ResponseStatus注解的异常以及@ExceptionHandler方法声明了内置的解析器。

容器错误页配置

如果任何HandlerExceptionResolver都无法解决异常,因此需要传播,或者响应状态被设置为错误状态(即4xx、5xx), Servlet容器可以在HTML中渲染一个默认的错误页面。要定制容器的默认错误页面,可以在web.xml中声明错误页面映射。如下面的例子所示:​


/error

根据前面的示例,当出现异常冒泡或响应具有错误状态时,Servlet容器将在容器中向配置的URL(例如/error)发送错误。然后由DispatcherServlet处理,可能会将其映射到一个@Controller,这个@Controller可以实现为返回一个带有模型的错误视图名称,或者渲染一个JSON响应,如下面的例子所示:​

@RestController
public class ErrorController {


@RequestMapping(path = "/error")
public Map handle(HttpServletRequest request) {
Map map = new HashMap();
map.put("status", request.getAttribute("javax.servlet.error.status_code"));
map.put("reason", request.getAttribute("javax.servlet.error.message"));
return map;
}
}

错误处理原理

public class DispatcherServlet {
// 取得容器中所有的异常解析器
private List handlerExceptionResolvers;
protected void initStrategies(ApplicationContext context) {
// 初始化异常解析器
initHandlerExceptionResolvers(context);
}
private void initHandlerExceptionResolvers(ApplicationContext context) {
this.handlerExceptionResolvers = null;
if (this.detectAllHandlerExceptionResolvers) {
// 获取容器中所有的异常解析器
Map matchingBeans = BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerExceptionResolver.class, true, false);
if (!matchingBeans.isEmpty()) {
this.handlerExceptionResolvers = new ArrayList<>(matchingBeans.values());
AnnotationAwareOrderComparator.sort(this.handlerExceptionResolvers);
}
}
}
}

发生异常后逻辑处理​

public class DispatcherServlet {
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
}
private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,
@Nullable HandlerExecutionChain mappedHandler, @Nullable ModelAndView mv,
@Nullable Exception exception) throws Exception {


boolean errorView = false;
// 判断当前调用是否发生了异常
if (exception != null) {
if (exception instanceof ModelAndViewDefiningException) {
mv = ((ModelAndViewDefiningException) exception).getModelAndView();
} else {
// 获取当前处理句柄HandlerMethod
Object handler = (mappedHandler != null ? mappedHandler.getHandler() : null);
// 处理异常
mv = processHandlerException(request, response, handler, exception);
errorView = (mv != null);
}
}
if (mv != null && !mv.wasCleared()) {
render(mv, request, response);
}
}
protected ModelAndView processHandlerException(HttpServletRequest request, HttpServletResponse response,
@Nullable Object handler, Exception ex) throws Exception {
request.removeAttribute(HandlerMapping.PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE);
ModelAndView exMv = null;
if (this.handlerExceptionResolvers != null) {
// 遍历在上面初始化查找到的所有异常解析器
for (HandlerExceptionResolver resolver : this.handlerExceptionResolvers) {
// 执行异常解析
exMv = resolver.resolveException(request, response, handler, ex);
if (exMv != null) {
break;
}
}
}
if (exMv != null) {
// ...
return exMv ;
}
// 如果所有的异常解析器都返回null,则直接抛出异常,该异常会被Servlet进行处理
throw ex ;
}
}

异常解析器默认配置

public class WebMvcAutoConfiguration {
@Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties(WebProperties.class)
public static class EnableWebMvcConfiguration extends DelegatingWebMvcConfiguration {
}
}
public class WebMvcConfigurationSupport {
@Bean
public HandlerExceptionResolver handlerExceptionResolver(@Qualifier("mvcContentNegotiationManager") ContentNegotiationManager contentNegotiationManager) {
List exceptionResolvers = new ArrayList<>();
// 处理自定义异常解析器的配置
configureHandlerExceptionResolvers(exceptionResolvers);
if (exceptionResolvers.isEmpty()) {
// 如果没有异常解析器,那么添加默认的异常解析器
addDefaultHandlerExceptionResolvers(exceptionResolvers, contentNegotiationManager);
}
extendHandlerExceptionResolvers(exceptionResolvers);
HandlerExceptionResolverComposite composite = new HandlerExceptionResolverComposite();
// 设置高优先级,Composite成为统一的入口
composite.setOrder(0);
composite.setExceptionResolvers(exceptionResolvers);
return composite;
}
// 默认配置
protected final void addDefaultHandlerExceptionResolvers(List exceptionResolvers, ContentNegotiationManager mvcContentNegotiationManager) {
ExceptionHandlerExceptionResolver exceptionHandlerResolver = createExceptionHandlerExceptionResolver();
exceptionHandlerResolver.setContentNegotiationManager(mvcContentNegotiationManager);
exceptionHandlerResolver.setMessageConverters(getMessageConverters());
exceptionHandlerResolver.setCustomArgumentResolvers(getArgumentResolvers());
exceptionHandlerResolver.setCustomReturnValueHandlers(getReturnValueHandlers());
if (jackson2Present) {
exceptionHandlerResolver.setResponseBodyAdvice(Collections.singletonList(new JsonViewResponseBodyAdvice()));
}
if (this.applicationContext != null) {
exceptionHandlerResolver.setApplicationContext(this.applicationContext);
}
exceptionHandlerResolver.afterPropertiesSet();
exceptionResolvers.add(exceptionHandlerResolver);
ResponseStatusExceptionResolver responseStatusResolver = new ResponseStatusExceptionResolver();
responseStatusResolver.setMessageSource(this.applicationContext);
exceptionResolvers.add(responseStatusResolver);
exceptionResolvers.add(new DefaultHandlerExceptionResolver());
}
}

完毕!!!

网页标题:SpringMVC核心功能异常处理机制原理详解
网址分享:http://www.shufengxianlan.com/qtweb/news29/403679.html

网站建设、网络推广公司-创新互联,是专注品牌与效果的网站制作,网络营销seo公司;服务项目有等

广告

声明:本网站发布的内容(图片、视频和文字)以用户投稿、用户转载内容为主,如果涉及侵权请尽快告知,我们将会在第一时间删除。文章观点不代表本网站立场,如需处理请联系客服。电话:028-86922220;邮箱:631063699@qq.com。内容未经允许不得转载,或转载时需注明来源: 创新互联