首先连按两下shift,输入ErrorMvcAutoConfiguration类,我们来简单说一下这个类中方法的作用:
这个方法中定义了异常数据
@Bean
@ConditionalOnMissingBean(
value = {ErrorAttributes.class},
search = SearchStrategy.CURRENT
)
public DefaultErrorAttributes errorAttributes() {
return new DefaultErrorAttributes(this.serverProperties.getError().isIncludeException());
}
默认视图解析器
@Bean
@ConditionalOnBean({DispatcherServlet.class})
@ConditionalOnMissingBean({ErrorViewResolver.class})
DefaultErrorViewResolver conventionErrorViewResolver() {
return new DefaultErrorViewResolver(this.applicationContext, this.resourceProperties);
}
我们知道springboot自动寻找异常类,先找动态再找静态,先找准确的再找模糊的。之所以是这样是因为与DefaultErrorViewResolver中定义的方法有关。
现在我们按住ctrl,点击DefaultErrorViewResolver类中查看,这个类中有一个关键的方法:
public ModelAndView resolveErrorView(HttpServletRequest request, HttpStatus status, Map<String, Object> model) {
ModelAndView modelAndView = this.resolve(String.valueOf(status.value()), model);
if (modelAndView == null && SERIES_VIEWS.containsKey(status.series())) {
modelAndView = this.resolve((String)SERIES_VIEWS.get(status.series()), model);
}
return modelAndView;
}
上面方法中接收的参数为:请求参数和异常数据。
首先调用resolve去获取ModelAndView(并且拿到具体的响应码,比如404,500…)。
现在我们来看一下获取的细节,按住ctrl点进resolve方法:
private ModelAndView resolve(String viewName, Map<String, Object> model) {
String errorViewName = "error/" + viewName;
TemplateAvailabilityProvider provider = this.templateAvailabilityProviders.getProvider(errorViewName, this.applicationContext);
return provider != null ? new ModelAndView(errorViewName, model) : this.resolveResource(errorViewName, model);
}
首先可以看到这个方法中给我们的viewName(其实就是响应码如404,500…)加了error前缀。(这也就可以解释为何我们要把定义的异常都放在error包下了)。
然后这个方法会查看有没有动态页面。
如果有动态页面则按住动态的来,如果没有则找静态页面(也就可以解释为何先找动态再找静态)。
然后按住ctrl点击resolveResource方法
首先查找四个默认包下的静态资源("classpath:/META-INF/resources/", "classpath:/resources/", "classpath:/static/", "classpath:/public/"
),看看能不能查到和状态码对应的文件。
找到文件之后自动在后加上html后缀。
然后再把文件渲染进页面。
private ModelAndView resolveResource(String viewName, Map<String, Object> model) {
String[] var3 = this.resourceProperties.getStaticLocations();
int var4 = var3.length;
for(int var5 = 0; var5 < var4; ++var5) {
String location = var3[var5];
try {
Resource resource = this.applicationContext.getResource(location);
resource = resource.createRelative(viewName + ".html");
if (resource.exists()) {
return new ModelAndView(new DefaultErrorViewResolver.HtmlResourceView(resource), model);
}
} catch (Exception var8) {
}
}
return null;
}
如果确定异常文件找不到,就去寻找模糊异常文件。
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);
}
到目前位置整个异常处理的流程就分析完毕了。