SpringBoot异常处理原理分析

springboot默认机制

错误处理的自动配置 都在ErrorMvcAutoConfiguration中,两大核心机制:

    1. SpringBoot 会自适应处理错误,响应页面或JSON数据
    1. SpringMVC的错误处理机制依然保留,MVC处理不了,才会交给boot进行处理
  • 发生错误以后,转发给/error路径,SpringBoot在底层写好一个 BasicErrorController的组件,专门处理这个请求
java 复制代码
	@RequestMapping(produces = MediaType.TEXT_HTML_VALUE) //返回HTML
	public ModelAndView errorHtml(HttpServletRequest request, HttpServletResponse response) {
		HttpStatus status = getStatus(request);
		Map<String, Object> model = Collections
			.unmodifiableMap(getErrorAttributes(request, getErrorAttributeOptions(request, MediaType.TEXT_HTML)));
		response.setStatus(status.value());
		ModelAndView modelAndView = resolveErrorView(request, response, status, model);
		return (modelAndView != null) ? modelAndView : new ModelAndView("error", model);
	}

	@RequestMapping  //返回 ResponseEntity, JSON
	public ResponseEntity<Map<String, Object>> error(HttpServletRequest request) {
		HttpStatus status = getStatus(request);
		if (status == HttpStatus.NO_CONTENT) {
			return new ResponseEntity<>(status);
		}
		Map<String, Object> body = getErrorAttributes(request, getErrorAttributeOptions(request, MediaType.ALL));
		return new ResponseEntity<>(body, status);
	}
  • 错误页面是这么解析到的
java 复制代码
//1、解析错误的自定义视图地址
ModelAndView modelAndView = resolveErrorView(request, response, status, model);
//2、如果解析不到错误页面的地址,默认的错误页就是 error
return (modelAndView != null) ? modelAndView : new ModelAndView("error", model);

容器中专门有一个错误视图解析器

java 复制代码
@Bean
@ConditionalOnBean(DispatcherServlet.class)
@ConditionalOnMissingBean(ErrorViewResolver.class)
DefaultErrorViewResolver conventionErrorViewResolver() {
    return new DefaultErrorViewResolver(this.applicationContext, this.resources);
}

SpringBoot解析自定义错误页的默认规则

java 复制代码
	@Override
	public ModelAndView resolveErrorView(HttpServletRequest request, HttpStatus status, Map<String, Object> model) {
		ModelAndView modelAndView = resolve(String.valueOf(status.value()), model);
		if (modelAndView == null && SERIES_VIEWS.containsKey(status.series())) {
			modelAndView = resolve(SERIES_VIEWS.get(status.series()), model);
		}
		return modelAndView;
	}

	private ModelAndView resolve(String viewName, Map<String, Object> model) {
		String errorViewName = "error/" + viewName;
		TemplateAvailabilityProvider provider = this.templateAvailabilityProviders.getProvider(errorViewName,
				this.applicationContext);
		if (provider != null) {
			return new ModelAndView(errorViewName, model);
		}
		return resolveResource(errorViewName, model);
	}

	private ModelAndView resolveResource(String viewName, Map<String, Object> model) {
		for (String location : this.resources.getStaticLocations()) {
			try {
				Resource resource = this.applicationContext.getResource(location);
				resource = resource.createRelative(viewName + ".html");
				if (resource.exists()) {
					return new ModelAndView(new HtmlResourceView(resource), model);
				}
			}
			catch (Exception ex) {
			}
		}
		return null;
	}

容器中有一个默认的名为 error 的 view; 提供了默认白页功能

java 复制代码
@Bean(name = "error")
@ConditionalOnMissingBean(name = "error")
public View defaultErrorView() {
    return this.defaultErrorView;
}

封装了JSON格式的错误信息

java 复制代码
	@Bean
	@ConditionalOnMissingBean(value = ErrorAttributes.class, search = SearchStrategy.CURRENT)
	public DefaultErrorAttributes errorAttributes() {
		return new DefaultErrorAttributes();
	}

规则:

  1. 解析一个错误页
    1. 如果发生了500、404、503、403 这些错误
      1. 如果有模板引擎 ,默认在 classpath:/templates/error/**精确码.html**
      2. 如果没有模板引擎,在静态资源文件夹下找 **精确码.html**
    2. 如果匹配不到精确码.html这些精确的错误页,就去找5xx.html4xx.html模糊匹配
      1. 如果有模板引擎,默认在 classpath:/templates/error/5xx.html
      2. 如果没有模板引擎,在静态资源文件夹下找 5xx.html
  2. 如果模板引擎路径templates下有 error.html页面,就直接渲染

springboot异常处理步骤流程

1、执行目标方法,目标方法运行期间有任何异常都会被catch、而且标志当前请求结束;并且用 **dispatchException **

2、进入视图解析流程(页面渲染?)

processDispatchResult(processedRequest, response, mappedHandler, mv , dispatchException );

3、**mv **= processHandlerException;处理handler发生的异常,处理完成返回ModelAndView;

  • 1、遍历所有的 handlerExceptionResolvers,看谁能处理当前异常【HandlerExceptionResolver处理器异常解析器】
  • 2、系统默认的 异常解析器;
    • 1、DefaultErrorAttributes先来处理异常。把异常信息保存到rrequest域,并且返回null;
    • 2、默认没有任何人能处理异常,所以异常会被抛出
      • 1、如果没有任何人能处理最终底层就会发送 /error 请求。会被底层的BasicErrorController处理
      • 2、解析错误视图;遍历所有的 ErrorViewResolver 看谁能解析。
      • **3、默认的 DefaultErrorViewResolver ,作用是把响应状态码作为错误页的地址,error/500.html **
      • **4、模板引擎最终响应这个页面 error/500.html **

最佳实战

  • 前后分离
    • 后台发生的所有错误, **@ControllerAdvice + @ExceptionHandler**进行统一异常处理。
  • 服务端页面渲染
    • 不可预知的一些,HTTP码表示的服务器或客户端错误
      • **classpath:/templates/error/**下面,放常用精确的错误码页面。 **500.html** **404.html**
      • **classpath:/templates/error/**下面,放通用模糊匹配的错误码页面。 **5xx.html** **4xx.html**
    • 发生业务错误
      • 核心业务,每一种错误,都应该代码控制,跳转到自己定制的错误页。
      • 通用业务, **classpath:/templates/error.html**页面,显示错误信息。

页面,JSON,可用的Model数据如下

相关推荐
小码哥_常3 小时前
别再被误导!try...catch性能大揭秘
后端
无巧不成书02185 小时前
30分钟入门Java:从历史到Hello World的小白指南
java·开发语言
苍何5 小时前
30分钟用 Agent 搓出一家跨境网店,疯了
后端
ssshooter6 小时前
Tauri 2 iOS 开发避坑指南:文件保存、Dialog 和 Documents 目录的那些坑
前端·后端·ios
追逐时光者6 小时前
一个基于 .NET Core + Vue3 构建的开源全栈平台 Admin 系统
后端·.net
程序员飞哥6 小时前
90后大龄程序员失业4个月终于上岸了
后端·面试·程序员
zs宝来了7 小时前
Playwright 自动发布 CSDN 的完整实践
java
彭于晏Yan7 小时前
Redisson分布式锁
spring boot·redis·分布式
吴声子夜歌8 小时前
TypeScript——基础类型(三)
java·linux·typescript
GetcharZp8 小时前
Git 命令行太痛苦?这款 75k Star 的神级工具,让你告别“合并冲突”恐惧症!
后端