微人事第四天:Spring Boot异常处理源码分析

首先连按两下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);
    }

到目前位置整个异常处理的流程就分析完毕了。

发布了287 篇原创文章 · 获赞 24 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/qq_41998938/article/details/104004616