溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

SpringBoot打印啟動時異常堆棧信息的示例分析

發布時間:2021-07-08 13:48:10 來源:億速云 閱讀:185 作者:小新 欄目:編程語言

這篇文章主要介紹了SpringBoot打印啟動時異常堆棧信息的示例分析,具有一定借鑒價值,感興趣的朋友可以參考下,希望大家閱讀完這篇文章之后大有收獲,下面讓小編帶著大家一起了解一下。

SpringBoot在項目啟動時如果遇到異常并不能友好的打印出具體的堆棧錯誤信息,我們只能查看到簡單的錯誤消息,以致于并不能及時解決發生的問題,針對這個問題SpringBoot提供了故障分析儀的概念(failure-analyzer),內部根據不同類型的異常提供了一些實現,我們如果想自定義該怎么去做?

FailureAnalyzer

SpringBoot提供了啟動異常分析接口FailureAnalyzer,該接口位于org.springframework.boot.diagnosticspackage內。
內部僅提供一個分析的方法,源碼如下所示:

@FunctionalInterface
public interface FailureAnalyzer {

 /**
  * Returns an analysis of the given {@code failure}, or {@code null} if no analysis
  * was possible.
  * @param failure the failure
  * @return the analysis or {@code null}
  */
 FailureAnalysis analyze(Throwable failure);

}

該接口會把遇到的異常對象實例Throwable failure交付給實現類,實現類進行自定義處理。

AbstractFailureAnalyzer

AbstractFailureAnalyzer是FailureAnalyzer的基礎實現抽象類,實現了FailureAnalyzer定義的analyze(Throwable failure)方法,并提供了一個指定異常類型的抽象方法analyze(Throwable rootFailure, T cause),源碼如下所示:

public abstract class AbstractFailureAnalyzer<T extends Throwable> implements FailureAnalyzer {

 @Override
 public FailureAnalysis analyze(Throwable failure) {
  T cause = findCause(failure, getCauseType());
  if (cause != null) {
   return analyze(failure, cause);
  }
  return null;
 }

 /**
  * Returns an analysis of the given {@code rootFailure}, or {@code null} if no
  * analysis was possible.
  * @param rootFailure the root failure passed to the analyzer
  * @param cause the actual found cause
  * @return the analysis or {@code null}
  */
 protected abstract FailureAnalysis analyze(Throwable rootFailure, T cause);

 /**
  * Return the cause type being handled by the analyzer. By default the class generic
  * is used.
  * @return the cause type
  */
 @SuppressWarnings("unchecked")
 protected Class<? extends T> getCauseType() {
  return (Class<? extends T>) ResolvableType.forClass(AbstractFailureAnalyzer.class, getClass()).resolveGeneric();
 }

 @SuppressWarnings("unchecked")
 protected final <E extends Throwable> E findCause(Throwable failure, Class<E> type) {
  while (failure != null) {
   if (type.isInstance(failure)) {
    return (E) failure;
   }
   failure = failure.getCause();
  }
  return null;
 }

}

通過AbstractFailureAnalyzer源碼我們可以看到,它在實現于FailureAnalyzer的接口方法內進行了特殊處理,根據getCauseType()方法獲取當前類定義的第一個泛型類型,也就是我們需要分析的指定異常類型。

獲取泛型異常類型后根據方法findCause判斷Throwable是否與泛型異常類型匹配,如果匹配直接返回給SpringBoot進行注冊處理。

SpringBoot提供的分析實現

SpringBoot內部通過實現AbstractFailureAnalyzer抽象類定義了一系列的針對性異常類型的啟動分析,如下圖所示:

SpringBoot打印啟動時異常堆棧信息的示例分析

指定異常分析

SpringBoot內部提供的啟動異常分析都是指定具體的異常類型實現的,最常見的一個錯誤就是端口號被占用(PortInUseException),雖然SpringBoot內部提供一個這個異常的啟動分析,我們也是可以進行替換這一異常分析的,我們只需要創建PortInUseException異常的AbstractFailureAnalyzer,并且實現類注冊給SpringBoot即可,實現自定義如下所示:

/**
 * 端口號被占用{@link PortInUseException}異常啟動分析
 *
 * @author 恒宇少年
 */
public class PortInUseFailureAnalyzer extends AbstractFailureAnalyzer<PortInUseException> {
 /**
  * logger instance
  */
 static Logger logger = LoggerFactory.getLogger(PortInUseFailureAnalyzer.class);

 @Override
 protected FailureAnalysis analyze(Throwable rootFailure, PortInUseException cause) {
  logger.error("端口被占用。", cause);
  return new FailureAnalysis("端口號:" + cause.getPort() + "被占用", "PortInUseException", rootFailure);
 }
}

注冊啟動異常分析

在上面我們只是編寫了指定異常啟動分析,我們接下來需要讓它生效,這個生效方式比較特殊,類似于自定義SpringBoot Starter AutoConfiguration的形式,我們需要在META-INF/spring.factories文件內進行定義,如下所示:

org.springframework.boot.diagnostics.FailureAnalyzer=\
 org.minbox.chapter.springboot.failure.analyzer.PortInUseFailureAnalyzer

那我們為什么需要使用這種方式定義呢?

項目啟動遇到的異常順序不能確定,很可能在Spring IOC并未執行初始化之前就出現了異常,我們不能通過@Component注解的形式使其生效,所以SpringBoot提供了通過spring.factories配置文件的方式定義。

啟動異常分析繼承關系

自定義的運行異常一般都是繼承自RuntimeException,如果我們定義一個RuntimeException的異常啟動分析實例會是什么效果呢?

/**
 * 項目啟動運行時異常{@link RuntimeException}統一啟動分析
 *
 * @author 恒宇少年
 */
public class ProjectBootUnifiedFailureAnalyzer extends AbstractFailureAnalyzer<RuntimeException> {
 /**
  * logger instance
  */
 static Logger logger = LoggerFactory.getLogger(ProjectBootUnifiedFailureAnalyzer.class);

 @Override
 protected FailureAnalysis analyze(Throwable rootFailure, RuntimeException cause) {
  logger.error("遇到運行時異常", cause);
  return new FailureAnalysis(cause.getMessage(), "error", rootFailure);
 }
}

將該類也一并注冊到spring.factories文件內,如下所示:

org.springframework.boot.diagnostics.FailureAnalyzer=\
 org.minbox.chapter.springboot.failure.analyzer.PortInUseFailureAnalyzer,\
 org.minbox.chapter.springboot.failure.analyzer.ProjectBootUnifiedFailureAnalyzer

運行項目并測試端口號被占用異常我們會發現,并沒有執行ProjectBootUnifiedFailureAnalyzer內的analyze方法,而是繼續執行了PortInUseFailureAnalyzer類內的方法。

那我們將PortInUseFailureAnalyzer這個啟動分析從spring.factories文件內暫時刪除掉,再來運行項目我們會發現這時卻是會執行ProjectBootUnifiedFailureAnalyzer類內分析方法。

感謝你能夠認真閱讀完這篇文章,希望小編分享的“SpringBoot打印啟動時異常堆棧信息的示例分析”這篇文章對大家有幫助,同時也希望大家多多支持億速云,關注億速云行業資訊頻道,更多相關知識等著你來學習!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

亚洲午夜精品一区二区_中文无码日韩欧免_久久香蕉精品视频_欧美主播一区二区三区美女