Springboot默认的错误页是如何工作及工作原理你肯定不知道?( 二 )

注册错误页面在上一步中知道了错误页的注册入口是在一个ErrorPageRegistrarBeanPostProcessor Bean后处理器中进行注册的,接下来继续深入查看这个错误页是如何被注册的 。
接着上一步在ErrorPageRegistrarBeanPostProcessor中查找ErrorPageRegistrar类型的Bean对象 。在另外一个自动配置中(ErrorMvcAutoConfiguration)有注册ErrorPageRegistrar Bean对象
@AutoConfigureBefore(WebMvcAutoConfiguration.class)@EnableConfigurationProperties({ ServerProperties.class, WebMvcProperties.class })public class ErrorMvcAutoConfiguration {// 该类是ErrorPageRegistrar子类,那么在注册错误页的时候注册的就是该类中生成的错误页信息static class ErrorPageCustomizer implements ErrorPageRegistrar, Ordered {private final ServerProperties properties;private final DispatcherServletPath dispatcherServletPath;protected ErrorPageCustomizer(ServerProperties properties, DispatcherServletPath dispatcherServletPath) {this.properties = properties;this.dispatcherServletPath = dispatcherServletPath;}@Overridepublic void registerErrorPages(ErrorPageRegistry errorPageRegistry) {// 错误页的地址可以在配置文件中自定义server.error.path进行配置,默认:/errorErrorPage errorPage = new ErrorPage(this.dispatcherServletPath.getRelativePath(this.properties.getError().getPath()));errorPageRegistry.addErrorPages(errorPage);}@Overridepublic int getOrder() {return 0;}}}关键代码
//errorPageRegistry对象的实例是TomcatServletWebServerFactory errorPageRegistry.addErrorPages(errorPage);TomcatServletWebServerFactory中注册错误页信息,该类的父类(AbstractConfigurableWebServerFactory)方法中有添加错误也的方法
public abstract class AbstractConfigurableWebServerFactory {private Set<ErrorPage> errorPages = new LinkedHashSet<>();public void addErrorPages(ErrorPage... errorPages) {this.errorPages.addAll(Arrays.asList(errorPages));}}这个错误页的注册到Tomcat容器中又是如何实现的呢?
Tomcat中注册错误页接下来看看这个错误页是如何与Tomcat关联在一起的 。
Spring容器最核心的方法是refresh方法
public abstract class AbstractApplicationContext {public void refresh() {// ...// Initialize other special beans in specific context subclasses.onRefresh();// ...}}执行onRefresh方法
public class ServletWebServerApplicationContext extends GenericWebApplicationContext {protected void onRefresh() {super.onRefresh();try {// 创建Tomcat服务createWebServer();} catch (Throwable ex) {throw new ApplicationContextException("Unable to start web server", ex);}}private void createWebServer() {// ...// 返回应用于创建嵌入的Web服务器的ServletWebServerFactory 。默认情况下,此方法在上下文本身中搜索合适的bean 。// 在上面ServletWebServerFactoryAutoConfiguration自动配置中,已经自动的根据当前的环境创建了TomcatServletWebServerFactory对象ServletWebServerFactory factory = getWebServerFactory();// 获取WebServer实例,factory = TomcatServletWebServerFactorythis.webServer = factory.getWebServer(getSelfInitializer());// ...}}调用TomcatServletWebServerFactory#getWebServer方法
public class TomcatServletWebServerFactory extends AbstractServletWebServerFactory {public WebServer getWebServer(ServletContextInitializer... initializers) {// ...Tomcat tomcat = new Tomcat();// ...// 预处理上下文prepareContext(tomcat.getHost(), initializers);return getTomcatWebServer(tomcat);}protected void prepareContext(Host host, ServletContextInitializer[] initializers) {// ...// 配置上下文configureContext(context, initializersToUse);}protected void configureContext(Context context, ServletContextInitializer[] initializers) {TomcatStarter starter = new TomcatStarter(initializers);// ...// 在这里就将错误的页面注册到了tomcat容器中for (ErrorPage errorPage : getErrorPages()) {org.Apache.tomcat.util.descriptor.web.ErrorPage tomcatErrorPage = new org.apache.tomcat.util.descriptor.web.ErrorPage();tomcatErrorPage.setLocation(errorPage.getPath());tomcatErrorPage.setErrorCode(errorPage.getStatusCode());tomcatErrorPage.setExceptionType(errorPage.getExceptionName());context.addErrorPage(tomcatErrorPage);}// ...}}到此你就知道了一个错误的页是如何在Springboot中被注册的 。到目前为止我们看到的注册到tomcat容器中的错误页都是个地址,比如:默认是/error 。那这个默认的/error又是怎么提供的接口呢?
默认错误页在Springboot中默认有个自动配置的错误页,在上面有一个代码片段你应该注意到了
@AutoConfigureBefore(WebMvcAutoConfiguration.class)@EnableConfigurationProperties({ ServerProperties.class, WebMvcProperties.class })public class ErrorMvcAutoConfiguration {@Bean@ConditionalOnMissingBean(value = https://www.isolves.com/it/cxkf/jiagou/2023-08-21/ErrorAttributes.class, search = SearchStrategy.CURRENT)public DefaultErrorAttributes errorAttributes() {return new DefaultErrorAttributes();}@Bean@ConditionalOnMissingBean(value = ErrorController.class, search = SearchStrategy.CURRENT)public BasicErrorController basicErrorController(ErrorAttributes errorAttributes, ObjectProvider


推荐阅读