日韩无码专区无码一级三级片|91人人爱网站中日韩无码电影|厨房大战丰满熟妇|AV高清无码在线免费观看|另类AV日韩少妇熟女|中文日本大黄一级黄色片|色情在线视频免费|亚洲成人特黄a片|黄片wwwav色图欧美|欧亚乱色一区二区三区

RELATEED CONSULTING
相關咨詢
選擇下列產(chǎn)品馬上在線溝通
服務時間:8:30-17:00
你可能遇到了下面的問題
關閉右側工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營銷解決方案
SpringBoot錯誤頁面的原理,你知道嗎?

環(huán)境:Springboot3.0.5

創(chuàng)新互聯(lián)公司主營七臺河網(wǎng)站建設的網(wǎng)絡公司,主營網(wǎng)站建設方案,重慶App定制開發(fā),七臺河h5微信平臺小程序開發(fā)搭建,七臺河網(wǎng)站營銷推廣歡迎七臺河等地區(qū)企業(yè)咨詢

錯誤消息格式

有如下接口:

@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返回如下:

后臺接口會根據(jù)不同的Accept返回不同的數(shù)據(jù)格式。

錯誤處理原理

Springboot在啟動過程中會執(zhí)行如下處理:

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

ServletWebServerApplicationContext

public class ServletWebServerApplicationContext {
  protected void onRefresh() {
    super.onRefresh();
    try {
      // 創(chuàng)建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) {
    // 創(chuàng)建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類實現(xiàn)了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實現(xiàn)了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是否實現(xiàn)了ErrorPageRegistry
    if (bean instanceof ErrorPageRegistry errorPageRegistry) {
      postProcessBeforeInitialization(errorPageRegistry);
    }
    return bean;
  }
  private void postProcessBeforeInitialization(ErrorPageRegistry registry) {
    // 遍歷所有的ErrorPageRegistrar,注冊到當前實現(xiàn)了ErrorPageRegistry接口的Bean中
    // 如上面的TomcatServletWebServerFactory
    for (ErrorPageRegistrar registrar : getRegistrars()) {
      registrar.registerErrorPages(registry);
    }
  }
  private Collection 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 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> error(HttpServletRequest request) {
    HttpStatus status = getStatus(request);
    if (status == HttpStatus.NO_CONTENT) {
      return new ResponseEntity<>(status);
    }
    Map body = getErrorAttributes(request, getErrorAttributeOptions(request, MediaType.ALL));
    return new ResponseEntity<>(body, status);
  }
}

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


標題名稱:SpringBoot錯誤頁面的原理,你知道嗎?
網(wǎng)站URL:http://www.5511xx.com/article/dppgopj.html