SpringBoot源码之BasicErrorController、DefaultErrorViewResolver、ErrorMvcAutoConfiguration类

当前源码:spring-boot 2.2.5.RELEASE版本!

1.声明

当前内容是用来了解和复习SpringBoot中的BasicErrorController源码的,在于一次配置了日志的时候发现访问一个错误的url产生的就是一个模板错误页面
在这里插入图片描述

使用springboot的时候产生这个肯定是访问路径没有被映射,所以才产生的

本人debug发现:
在这里插入图片描述

发现这个无论访问任何不存在的url都会调用BasicErrorController中的errorHtml方法!(所以本人决定解析这个类,并了解作用)

2.分析BasicErrorController类

首先通过名字发现BasicErrorController就是一个基本错误控制器就是一个Controller,也就是说spring可能使用@Controller注解,其方法中必定有@RequestMapping用来处理error问题

1.查看这个类的注解

@Controller
@RequestMapping("${server.error.path:${error.path:/error}}") 
public class BasicErrorController extends AbstractErrorController {
}

发现@RequestMapping("${server.error.path:${error.path:/error}}") ,可能就是用来匹配路径为/error的,本人表示有点不明白!就是使用了@Controller

2.查看这个类调用的errorHtml方法

// 表示当前响应为html/text
@RequestMapping(produces = MediaType.TEXT_HTML_VALUE)
	public ModelAndView errorHtml(HttpServletRequest request, HttpServletResponse response) {
		HttpStatus status = getStatus(request); // 获取http状态码
		// 获取错误的model(不可修改的)
		Map<String, Object> model = Collections
				.unmodifiableMap(getErrorAttributes(request, isIncludeStackTrace(request, MediaType.TEXT_HTML)));
		response.setStatus(status.value()); // 设置响应状态码
		// 计息错误视图并返回
		ModelAndView modelAndView = resolveErrorView(request, response, status, model);
		return (modelAndView != null) ? modelAndView : new ModelAndView("error", model);
	}

发现该方法就是一个设置返回为html/text,并且居于状态码,并产生modelAndView的方法

由于返回的ModelAndView是需要通过ViewResolver进行解析的成view才能返回的,所以继续找到对应的错误视图解析器

3.找到错误视图解析器

1.查看当前BasicErrorController所在的包,结果如下
在这里插入图片描述
我们发现了ErrorViewResolver和DefaultErrorViewResolver(所以可以判断spring中默认就是使用DefaultErrorViewResolver进行解析的

ErrorMvcAutoConfiguration这个类应该就是Error视图自动配置类(访问不存在的url的配置类)

4.查看DefaultErrorViewResolver类源码

查看这个类的静态代码块:

static {
		Map<Series, String> views = new EnumMap<>(Series.class);
		views.put(Series.CLIENT_ERROR, "4xx");
		views.put(Series.SERVER_ERROR, "5xx");
		SERIES_VIEWS = Collections.unmodifiableMap(views);
	}

默认项SERIES_VIEWS 中添加了错误代码,分为客户端错误:4XX和服务器错误:5XX,并且是不可修改的Map集合

查看解析视图的方法

   // 解析错误的视图
	@Override
	public ModelAndView resolveErrorView(HttpServletRequest request, HttpStatus status, Map<String, Object> model) {
		// 传递当前的 HttpStatus 中的状态码:即4xx,5xx
		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;
	}
	//通过视图名称和model解析视图
	private ModelAndView resolve(String viewName, Map<String, Object> model) {
		String errorViewName = "error/" + viewName; // 为error/4xx,5xx
		TemplateAvailabilityProvider provider = this.templateAvailabilityProviders.getProvider(errorViewName,
				this.applicationContext); // 判断是否存在模板
		if (provider != null) { // 存在就返回模板视图
			return new ModelAndView(errorViewName, model);
		}
		return resolveResource(errorViewName, model); // 否则返回资源视图(即当前文件error/中存在4xx或者5xx的html页面)
	}
	
	// 按照名称和model解析资源视图
	private ModelAndView resolveResource(String viewName, Map<String, Object> model) {
		// 获取静态资源路径
		for (String location : this.resourceProperties.getStaticLocations()) {
			try {
				// 通过路径获取resource
				Resource resource = this.applicationContext.getResource(location);
				resource = resource.createRelative(viewName + ".html"); // 通过error/4xx.html等是否存在
				if (resource.exists()) {
				    // 存在就返回他
					return new ModelAndView(new HtmlResourceView(resource), model);
				}
			}
			catch (Exception ex) {
			}
		}
		return null;
	}

这里发现了HtmlResourceView这个内部类

private static class HtmlResourceView implements View {

		private Resource resource;

		HtmlResourceView(Resource resource) {
			this.resource = resource;
		}

		@Override
		public String getContentType() {
			return MediaType.TEXT_HTML_VALUE;
		}
		// 发现所有的view中都是具有这个方法的,所以通过这个方法可以实现所有的视图转发
		@Override
		public void render(Map<String, ?> model, HttpServletRequest request, HttpServletResponse response)
				throws Exception {
				// 设置响应类型
			response.setContentType(getContentType());
			// 将当前的html文件读入为输入流,并写入到响应流中
			FileCopyUtils.copy(this.resource.getInputStream(), response.getOutputStream());
		}

	}

通过上面发现,为什么我们在resources文件中添加了error文件夹,并创建4xx.html,或者5xx.html的时候可以被springboot自动解析并在页面显示

5.现在来看ErrorMvcAutoConfiguration

首先通过ErrorMvcAutoConfiguration名称发现,这是一个错误mvc自动配置类,所以这个类必须有@Configuration注解

1.查看这个类的注解

@Configuration(proxyBeanMethods = false)
@ConditionalOnWebApplication(type = Type.SERVLET)
@ConditionalOnClass({ Servlet.class, DispatcherServlet.class })
// Load before the main WebMvcAutoConfiguration so that the error View is available
@AutoConfigureBefore(WebMvcAutoConfiguration.class)
@EnableConfigurationProperties({ ServerProperties.class, ResourceProperties.class, WebMvcProperties.class })

发现这个类在web应用中并且类型是Servlet在会创建,并且容器中必须有Servlet和DispatcherServlet存在,必须在WebMvcAutoConfiguration前面启动配置

==2.发现这个类中定义了很多bean,并且确实注入了BasicErrorController ==

@Bean
	@ConditionalOnMissingBean(value = ErrorController.class, search = SearchStrategy.CURRENT)
	public BasicErrorController basicErrorController(ErrorAttributes errorAttributes,
			ObjectProvider<ErrorViewResolver> errorViewResolvers) {
		return new BasicErrorController(errorAttributes, this.serverProperties.getError(),
				errorViewResolvers.orderedStream().collect(Collectors.toList()));
	}

3.发现这个类的静态内部类DefaultErrorViewResolverConfiguration(又是一个配置类),发现这个类中注入了DefaultErrorViewResolver这个错误视图解析器!

@Bean
		@ConditionalOnBean(DispatcherServlet.class)
		@ConditionalOnMissingBean(ErrorViewResolver.class)
		DefaultErrorViewResolver conventionErrorViewResolver() {
			return new DefaultErrorViewResolver(this.applicationContext, this.resourceProperties);
		}

==4.继续查看WhitelabelErrorViewConfiguration这个配置类,发现了StaticView ==

private final StaticView defaultErrorView = new StaticView();

		@Bean(name = "error")
		@ConditionalOnMissingBean(name = "error")
		public View defaultErrorView() {
			return this.defaultErrorView;
		}

发现这个类名字叫error,估计有什么特殊作用

5.继续查看StaticView类

在这里插入图片描述
发现这个内容很熟悉
在这里插入图片描述
发现结果就是这个,所以当我们访问一个不存在的url的时候就会创建StaticView,并启用render方法,写出一个text/html的模板信息

6.总结

1.我们使用Springboot访问一个不存在的url的时候,默认会创建error映射,并使用BasicErrorController中的@RequestMapping

2.当BasicErrorController中的对应的@RequestMapping方法处理完后返回ModelAndView,就需要通过DefaultErrorViewResolver来解析并获取View

3.当前解析的时候默认会使用StaticView来解析并生成(调用render方法)模板返回

4.SpringBoot之所以这个简单,是因为ErrorMvcAutoConfiguration在启动的时候就被加载了各种需要的配置类,它将我们需要的东西都配置好了,所以我们使用起来很简单

以上纯属个人见解,如有问题请联系本人!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
根据引用\[1\]和引用\[2\]中的信息,BasicErrorController是Spring Boot默认的异常处理。它负责处理错误请求并返回相应的错误页面。在Templates文件夹中,error.html页面会自动跳转,而error/404.html页面也会自动跳转。这是因为BasicErrorController中的配置决定了这种行为。具体来说,BasicErrorController中的basicErrorController方法使用了ErrorAttributes和ErrorViewResolvers来处理错误请求并返回相应的视图。如果你想解决BasicErrorController_error,你可以覆盖自定义异常处理。你可以实现ErrorController接口,或者继承AbstractErrorControllerBasicErrorController,并重写相应的方法来处理异常。这样就可以自定义错误处理逻辑,使原有的异常失效。\[3\] #### 引用[.reference_title] - *1* [SpringBoot异常处理机制-BasicErrorController与@ControllerAdvice](https://blog.csdn.net/weixin_40598838/article/details/108126111)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* *3* [SpringBoot源码~揭秘异常处理过程BasicErrorController](https://blog.csdn.net/qq_38939215/article/details/110240044)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值