成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

SpringBoot錯誤頁面的原理,你知道嗎?

開發 前端
通過分析,默認情況下springboot容器啟動后會像tomcat容器中注冊一個/error的錯誤頁,這個/error又是誰呢?

環境:Springboot3.0.5

錯誤消息格式

有如下接口:

@RestController
@RequestMapping("/demo")
public class DemoController {


  @GetMapping("/index")
  public Object index() {
    System.out.println(1 / 0) ;
    return "/demo/index" ;
  }
  
}

當訪問上面接口后,默認情況下Springboot會返回如下錯誤信息:

圖片

當請求的Accept是text/html返回的是HTML結果,當Accpet是application/json返回如下:

圖片

后臺接口會根據不同的Accept返回不同的數據格式。

錯誤處理原理

Springboot在啟動過程中會執行如下處理:

public abstract class AbstractApplicationContext {
  public void refresh() {
    onRefresh();
  }
}

ServletWebServerApplicationContext

public class ServletWebServerApplicationContext {
  protected void onRefresh() {
    super.onRefresh();
    try {
      // 創建web服務
      createWebServer();
    } catch (Throwable ex) {
      throw new ApplicationContextException("Unable to start web server", ex);
    }
  }
  private void createWebServer() {
    // 這里假設我們使用的是Tomcat容器,那么這里的factory = TomcatServletWebServerFactory
    this.webServer = factory.getWebServer(getSelfInitializer());
  }
}

TomcatServletWebServerFactory

public class TomcatServletWebServerFactory {
  public WebServer getWebServer(ServletContextInitializer... initializers) {
    // 創建Tomcat實例
    Tomcat tomcat = new Tomcat();
    // ...
    // 準備上下文
    prepareContext(tomcat.getHost(), initializers);
    return getTomcatWebServer(tomcat);
  }
  protected void prepareContext(Host host, ServletContextInitializer[] initializers) {
    // 該類繼承自StandardContext類(該類所屬tomcat,每一個StandardContext代表了一個webapp)
    TomcatEmbeddedContext context = new TomcatEmbeddedContext();
    // ...
    // 配置上下文
    configureContext(context, initializersToUse);
  }
  // 配置上下文
  protected void configureContext(Context context, ServletContextInitializer[] initializers) {
    // 獲取當前Spring容器中配置的ErrorPage,然后注冊到Tomcat當前webapp的上下文中
    // 這里其實對應的就是web.xml中配置的錯誤頁
    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);
    }
  }
}

TomcatServletWebServerFactory類實現了ErrorPageRegistry接口,有如下方法:

// TomcatServletWebServerFactory繼承自AbstractConfigurableWebServerFactory
// ConfigurableWebServerFactory接口繼承了ErrorPageRegistry接口
public abstract class AbstractConfigurableWebServerFactory implements ConfigurableWebServerFactory {
  public void addErrorPages(ErrorPage... errorPages) {
    this.errorPages.addAll(Arrays.asList(errorPages));
  }
}

下面查看上面的addErrorPages方法是如何被調用的。

在自動配置類中導入了下面的類

@Import({ ServletWebServerFactoryAutoConfiguration.BeanPostProcessorsRegistrar.class})
public class ServletWebServerFactoryAutoConfiguration {
}
// BeanPostProcessorsRegistrar實現了ImportBeanDefinitionRegistrar,用來注冊Bean
public static class BeanPostProcessorsRegistrar implements ImportBeanDefinitionRegistrar, BeanFactoryAware {
  public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
    // 注冊了BeanPostProcessor類ErrorPageRegistrarBeanPostProcessor
    registerSyntheticBeanIfMissing(registry, "errorPageRegistrarBeanPostProcessor", ErrorPageRegistrarBeanPostProcessor.class);
  }
}
public class ErrorPageRegistrarBeanPostProcessor implements BeanPostProcessor, BeanFactoryAware {
  public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
    // 判斷當前的Bean是否實現了ErrorPageRegistry
    if (bean instanceof ErrorPageRegistry errorPageRegistry) {
      postProcessBeforeInitialization(errorPageRegistry);
    }
    return bean;
  }
  private void postProcessBeforeInitialization(ErrorPageRegistry registry) {
    // 遍歷所有的ErrorPageRegistrar,注冊到當前實現了ErrorPageRegistry接口的Bean中
    // 如上面的TomcatServletWebServerFactory
    for (ErrorPageRegistrar registrar : getRegistrars()) {
      registrar.registerErrorPages(registry);
    }
  }
  private Collection<ErrorPageRegistrar> getRegistrars() {
    if (this.registrars == null) {
      // 獲取容器中所有的ErrorPageRegistrar Bean對象
      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;
  }
}

接下來就是從容器中獲取ErrorPageRegistrar,然后注冊到ErrorPageRegistry中。

在如下自動配置類中定義了一個默認的錯誤頁對象。

public class ErrorMvcAutoConfiguration {
  @Bean
  public ErrorPageCustomizer errorPageCustomizer(DispatcherServletPath dispatcherServletPath) {
    return new ErrorPageCustomizer(this.serverProperties, dispatcherServletPath);
  }
  static class ErrorPageCustomizer implements ErrorPageRegistrar, Ordered {
    // springboot配置文件中的server接口中獲取error配置信息
    private final ServerProperties properties;


    private final DispatcherServletPath dispatcherServletPath;


    protected ErrorPageCustomizer(ServerProperties properties, DispatcherServletPath dispatcherServletPath) {
      this.properties = properties;
      this.dispatcherServletPath = dispatcherServletPath;
    }


    @Override
    public void registerErrorPages(ErrorPageRegistry errorPageRegistry) {
      // 獲取server.error.path配置屬性
      ErrorPage errorPage = new ErrorPage(this.dispatcherServletPath.getRelativePath(this.properties.getError().getPath()));
      errorPageRegistry.addErrorPages(errorPage);
    }
  }
}
@ConfigurationProperties(prefix = "server", ignoreUnknownFields = true)
public class ServerProperties {
  @NestedConfigurationProperty
  private final ErrorProperties error = new ErrorProperties();
}
public class ErrorProperties {
  // 讀取error.path配置,如果沒有配置,則默認是/error
  @Value("${error.path:/error}")
  private String path = "/error";
}

通過上面的分析,默認情況下springboot容器啟動后會像tomcat容器中注冊一個/error的錯誤頁,這個/error又是誰呢?

默認錯誤Controller

在默認的錯誤頁自動配置中:

public class ErrorMvcAutoConfiguration {
  @Bean
  @ConditionalOnMissingBean(value = ErrorAttributes.class, search = SearchStrategy.CURRENT)
  public DefaultErrorAttributes errorAttributes() {
    return new DefaultErrorAttributes();
  }


  // 該Controller就是默認的/error錯誤跳轉的類
  @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().toList());
  }
}
@Controller
@RequestMapping("${server.error.path:${error.path:/error}}")
public class BasicErrorController extends AbstractErrorController {
  // 當請求的Accept=text/html時調用該方法
  @RequestMapping(produces = MediaType.TEXT_HTML_VALUE)
  public ModelAndView errorHtml(HttpServletRequest request, HttpServletResponse response) {
    // ...
  }
  // 當請求的Accept=application/json時調用該方法
  @RequestMapping
  public ResponseEntity<Map<String, Object>> error(HttpServletRequest request) {
    HttpStatus status = getStatus(request);
    if (status == HttpStatus.NO_CONTENT) {
      return new ResponseEntity<>(status);
    }
    Map<String, Object> body = getErrorAttributes(request, getErrorAttributeOptions(request, MediaType.ALL));
    return new ResponseEntity<>(body, status);
  }
}

以上就是當springboot默認情況下發生錯誤時的執行輸出原理。

責任編輯:武曉燕 來源: 實戰案例錦集
相關推薦

2024-02-19 00:00:00

Console函數鏈接庫

2024-02-26 08:19:00

WebSpring容器

2023-12-20 08:23:53

NIO組件非阻塞

2023-12-12 08:41:01

2023-04-26 10:21:04

2024-04-30 09:02:48

2024-05-28 09:12:10

2024-04-07 00:00:00

ESlint命令變量

2024-01-09 07:29:05

Argo代碼庫應用程序

2020-10-28 11:20:55

vue項目技

2019-12-12 09:23:29

Hello World操作系統函數庫

2017-10-16 13:45:04

2024-07-30 08:22:47

API前端網關

2022-05-27 08:55:15

工具自動化軟件

2022-03-10 08:25:27

JavaScrip變量作用域

2022-06-24 08:20:04

CAP網絡通信

2021-02-02 08:21:28

網絡面試通信

2024-10-10 16:53:53

守護線程編程

2019-06-14 15:36:13

Windows 10安全PC

2024-04-07 00:00:03

點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 麻豆av片 | 国产精品久久久久婷婷二区次 | 黄色大片在线免费观看 | 久久午夜电影 | 黄色亚洲 | 欧美亚洲一级 | 欧美日韩国产高清 | 欧洲亚洲一区 | 99视频在线免费观看 | 欧美日韩在线精品 | 久久精品国产免费高清 | av一二三区 | 免费污视频 | 欧美激情久久久 | 亚洲狠狠 | 国产精品毛片一区二区在线看 | 中文成人无字幕乱码精品 | 国产精品久久国产精品 | 人人做人人澡人人爽欧美 | 久久黄色精品视频 | 99福利视频导航 | 91精品国产综合久久久久久 | 黄色一级特级片 | 伊人网综合在线观看 | 中文字幕日韩一区 | 2019中文字幕视频 | 久久久久亚洲视频 | 亚洲一区视频在线播放 | 亚洲精品成人在线 | 一级黄色片免费 | 国产一级一级 | 成人免费区一区二区三区 | 欧美中文一区 | 亚洲91精品| 亚洲欧美综合精品另类天天更新 | 成人1区| 青青草一区二区三区 | 亚洲一区免费在线 | 日韩中文字幕免费 | 久久久91精品国产一区二区精品 | 看av网址 |