Springboot sentiment edify-web configuration (ii)

Source: Internet
Author: User
Tags assert

To undertake the former Wen springboot sentiment edify-web configuration (i), before analyzing the configuration of MVC, first understand how its default error interface is displayed

404 interface

Springboot has a more interesting configuration server.error.whitelabel.enabled, can be used to manage the display of the 404 interface, is a simple display or detailed display.
When you specify false , you will simply display an error message that the view cannot find, as follows

When specified as true (the default configuration), the error message in the previous sample is displayed, as follows

Source Layer Analysis

Springboot arranged the errormvcautoconfiguration automatic configuration class to handle the error page information, the author divided into several steps to analyze

The annotations on the top skull look

@Configuration@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 })public class ErrorMvcAutoConfiguration {}

You can see that it was before the webmvcautoconfiguration configuration class, so why should it be in front? Look at the note is that this can make the error view valid, how to achieve it? The author continues to explore with questions

No.2 defaulterrorviewresolverconfiguration internal Class-Error view resolver registration

    @Configuration    static class DefaultErrorViewResolverConfiguration {        private final ApplicationContext applicationContext;        private final ResourceProperties resourceProperties;        DefaultErrorViewResolverConfiguration(ApplicationContext applicationContext,                ResourceProperties resourceProperties) {            this.applicationContext = applicationContext;            this.resourceProperties = resourceProperties;        }        // 注册了DefaultErrorViewResolver解析器        @Bean        @ConditionalOnBean(DispatcherServlet.class)        @ConditionalOnMissingBean        public DefaultErrorViewResolver conventionErrorViewResolver() {            return new DefaultErrorViewResolver(this.applicationContext,                    this.resourceProperties);        }    }

defaulterrorviewresolver This default error view parser is interesting, it contains some of the default processing, but also a few small steps to it, it will appear clear

    • static method Understanding
    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);    }

should be the HTTP status Code mapping processing, starting with 4 is a client error, 5 starts with a server error

    • Constructor to understand
    public DefaultErrorViewResolver(ApplicationContext applicationContext,            ResourceProperties resourceProperties) {        Assert.notNull(applicationContext, "ApplicationContext must not be null");        Assert.notNull(resourceProperties, "ResourceProperties must not be null");        this.applicationContext = applicationContext;        this.resourceProperties = resourceProperties;        // 模板加载器        this.templateAvailabilityProviders = new TemplateAvailabilityProviders(                applicationContext);    }

The above-mentioned template loader is mainly to read all spring.factories in the org.springframework.boot.autoconfigure.template.TemplateAvailabilityProvider corresponding property values, essentially the template renderer, such as our common freemarker, velocity, JSP and so on

    • View Object Get Understanding
    @Override public Modelandview Resolveerrorview (httpservletrequest request, httpstatus status, Map<str ING, object> model) {//priority to find the view static resource based on the status code, such as 404 will find error/404 view Modelandview modelandview = Resolve (stri        Ng.valueof (status), model); if (Modelandview = = null && series_views.containskey (Status.series ())) {//The above does not exist then find error/4xx or ERROR/5        XX View Modelandview = Resolve (Series_views.get (Status.series ()), model);    } return Modelandview; } Private Modelandview Resolve (string viewName, map<string, object> model) {String errorviewname = "Error        /"+ ViewName;                Find out if the required view resources are included through the template loader Templateavailabilityprovider Provider = This.templateavailabilityproviders        . Getprovider (Errorviewname, This.applicationcontext);        if (provider! = NULL) {return new Modelandview (errorviewname, model);    } return ResolveResource (Errorviewname, model); }       The default lookup staticlocation resources for the specified path, such as classpath:/static/error/404.html private Modelandview resolveresource (String view            Name, map<string, object> model) {for (String location:this.resourceProperties.getStaticLocations ()) {                try {Resource Resource = this.applicationContext.getResource (location);                Resource = resource.createrelative (ViewName + ". html"); if (resource.exists ()) {//view type is Htmlresourceview, output HTML resource directly to response object return n                EW Modelandview (New Htmlresourceview (Resource), model);    }} catch (Exception ex) {}} return null; }

Through the above code comments, the basic can know the error view of the lookup rules, so users can simply configure the static directory corresponding to the status code of the page such as error/404.html or error/500.html Or, of course, you can configure a unified page error/4xx.html or error/5xx.html

So if we don't specify anything, how does the above error message show up?

No.3 whitelabelerrorviewconfiguration-Whiteboard Error View configuration

    The server.error.whitelabel.enabled switch, by default, is an open @Configuration @ConditionalOnProperty (prefix = "Server.error.whitela Bel ", name =" Enabled ", matchifmissing = True) @Conditional (errortemplatemissingcondition.class) protected static CL Whitelabelerrorviewconfiguration {//Familiar printing information private final spelview Defaulterrorview = new Spel View ("

The above is where the error message is visible at the beginning of the processing, the detailed user can consult the code

No.4 Constructors Understand

    public ErrorMvcAutoConfiguration(ServerProperties serverProperties,            ObjectProvider<List<ErrorViewResolver>> errorViewResolversProvider) {        this.serverProperties = serverProperties;        this.errorViewResolvers = errorViewResolversProvider.getIfAvailable();    }

The above Errorviewresolverprovider will load the second step of the defaultviewresolver, of course, users can also customize to implement Errorviewresolver interface. These erroneous view parsers will be called at the controller layer in the next step

No.5 Error Controller Registration

    @Bean    @ConditionalOnMissingBean(value = ErrorAttributes.class, search = SearchStrategy.CURRENT)    public DefaultErrorAttributes errorAttributes() {        return new DefaultErrorAttributes(                this.serverProperties.getError().isIncludeException());    }    // 创建BasicErrorController控制器用于响应server.error.path指定的路径,默认为/error    @Bean    @ConditionalOnMissingBean(value = ErrorController.class, search = SearchStrategy.CURRENT)    public BasicErrorController basicErrorController(ErrorAttributes errorAttributes) {        return new BasicErrorController(errorAttributes, this.serverProperties.getError(),                this.errorViewResolvers);    }

The Basicerrorcontroller object here responds to /error 's request by default, and it internally writes a response method that returns an HTML page

    @RequestMapping(produces = "text/html")    public ModelAndView errorHtml(HttpServletRequest request,            HttpServletResponse response) {        HttpStatus status = getStatus(request);        Map<String, Object> model = Collections.unmodifiableMap(getErrorAttributes(                request, isIncludeStackTrace(request, MediaType.TEXT_HTML)));        // 状态码设置        response.setStatus(status.value());        // 调用errorViewResolvers集合去获取对应的错误视图        ModelAndView modelAndView = resolveErrorView(request, response, status, model);        // 如果没指定相应的视图,则会采用默认的名为error的视图        return (modelAndView != null ? modelAndView : new ModelAndView("error", model));    }

Make a simple explanation of the above code comments to help readers straighten out their ideas

    1. First, it calls all the view parsers that implement the Errorviewresolver interface to find the appropriate error view and to support ordering through the order interface. So here by default, Defaulterrorviewresolver is called to get the view, specifically if you get the visual explanation above
    2. If the above is found, then it is a matter of, but if not found, it will default to specify the view named error .
    3. So how do you parse a view that is named error by default? The answer is that when Dispatcherservlet finally determines the rendering view, all the view parsers that implement the Viewresolver interface are called uniformly to get the view object, then the third step The Beannameviewresolver object will find the corresponding Spelview view and render it accordingly.

Here I answer the beginning of the question, why errormvcautoconfiguration need to put before dispatcherservletautoconfiguration , In fact the main thing is that the latter did not go to register beanviewresolver, here on an insurance, so that can correctly find spelview Object

Error request problem

After the above analysis, we know that Basicerrorcontroller is used to handle requests for access to get [/error] and to handle the corresponding error view, then the most important problem comes, In the end, how can the resources not be found in the path from this route? I continue to explore with this problem

Top errorpagecustomizer-Error page configuration

  @Bean public Errorpagecustomizer Errorpagecustomizer () {return new Errorpagecustomi    Zer (this.serverproperties); } private static Class Errorpagecustomizer implements Errorpageregistrar, Ordered {private final Serverproperti        ES properties;        Protected Errorpagecustomizer (Serverproperties properties) {this.properties = properties;            } @Override public void Registererrorpages (Errorpageregistry errorpageregistry) {//default path is/error                            ErrorPage errorpage = new ErrorPage (This.properties.getServlet (). Getservletprefix ()            + This.properties.getError (). GetPath ());        Registered errorpageregistry.adderrorpages (errorpage);        } @Override public int getorder () {return 0; }    }

The above ErrorPage seems to show a bit of information, it may be to visit the source of /error , then errorpagecustomizer#registererrorpages () is how to be called? Continue down.

No.2 Servletwebautoconfiguration in the introduction of the time also registered a beanpostprocessor

        @Override        public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata,                BeanDefinitionRegistry registry) {            if (this.beanFactory == null) {                return;            }            registerSyntheticBeanIfMissing(registry,                    "webServerFactoryCustomizerBeanPostProcessor",                    WebServerFactoryCustomizerBeanPostProcessor.class);            // 就是这个            registerSyntheticBeanIfMissing(registry,                    "errorPageRegistrarBeanPostProcessor",                    ErrorPageRegistrarBeanPostProcessor.class);        }

We're going to focus on its main approach.

    // 注册了相应的错误界面    private void postProcessBeforeInitialization(ErrorPageRegistry registry) {        for (ErrorPageRegistrar registrar : getRegistrars()) {            registrar.registerErrorPages(registry);        }    }    private Collection<ErrorPageRegistrar> getRegistrars() {        if (this.registrars == null) {            // Look up does not include the parent context            this.registrars = new ArrayList<>(this.beanFactory                    .getBeansOfType(ErrorPageRegistrar.class, false, false).values());            this.registrars.sort(AnnotationAwareOrderComparator.INSTANCE);            this.registrars = Collections.unmodifiableList(this.registrars);        }        return this.registrars;    }

As to why in this class to register the processor to execute the registration error page, it appears that the forwarding of this path should be related to the Web container. In fact, tracing the source of the error interface into the corresponding Web container (TOMCAT), the specific reader can self-analysis.

No.4 Web Container Loading (episode, incidentally)
we all know that Springboot uses the applicationcontext for the environment as the servlet Annotationconfigservletwebserverapplicationcontext , whose parent is the Onrefresh () method in the refresh context procedure, launches the Web container

    @Override protected void Onrefresh () {Super.onrefresh ();        try {//Create Web server Createwebserver ();        } catch (Throwable ex) {throw new Applicationcontextexception ("Unable to start Web server", ex);        }} private void Createwebserver () {WebServer WebServer = this.webserver;        ServletContext ServletContext = Getservletcontext (); if (WebServer = = NULL && ServletContext = = null) {//default = Tomcatservletwebserverfactory SERVL            Etwebserverfactory factory = Getwebserverfactory ();        Initialize servlet/filter et this.webserver = Factory.getwebserver (Getselfinitializer ()); } else if (ServletContext! = null) {try {Getselfinitializer (). Onstartup (ServletContext)            ;  } catch (Servletexception ex) {throw new Applicationcontextexception ("Cannot initialize servlet                        Context ",ex);    }} initpropertysources (); }

the code above mainly registers the filters and Servlets collections on ServletContext and registers the Errorpages, limited to the code too long, which the reader can analyze on its own. and the specific way to start the Web container is in the Finishrefresh () method

    @Override    protected void finishRefresh() {        super.finishRefresh();        // 启动        WebServer webServer = startWebServer();        if (webServer != null) {            publishEvent(new ServletWebServerInitializedEvent(webServer, this));        }    }

No.5 standardhostvalve-Error Interface application

    private void status(Request request, Response response) {        int statusCode = response.getStatus();        ....        // 优先查找404对应的ErrorPage        ErrorPage errorPage = context.findErrorPage(statusCode);        if (errorPage == null) {            // 0-默认的ErrorPage,此处便是上文注册的            errorPage = context.findErrorPage(0);        }        if (errorPage != null && response.isErrorReportRequired()) {            ....        }    }

This source is from Tomcat, which reminds me of the page configuration for the status code

    <!--404 error page specified based on Tomcat-->    <error-page>        <error-code>404</error-code>        <location>/404.html</location>    </error-page>
Summary

The content of this article is more, need to be patient to read, the reader only need to understand the view view of the analytic loading can read through the full text, if you want to customize the status Code view directly in the classpath:/static/error directory to create a corresponding status code HTML file, Refer to this article for details.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.