SpringBoot打印詳細(xì)啟動(dòng)異常信息
SpringBoot在項(xiàng)目啟動(dòng)時(shí)如果遇到異常并不能友好的打印出具體的堆棧錯(cuò)誤信息,我們只能查看到簡(jiǎn)單的錯(cuò)誤消息,以致于并不能及時(shí)解決發(fā)生的問(wèn)題,針對(duì)這個(gè)問(wèn)題SpringBoot提供了故障分析儀的概念(failure-analyzer),內(nèi)部根據(jù)不同類型的異常提供了一些實(shí)現(xiàn),我們?nèi)绻胱远x該怎么去做?
FailureAnalyzer
SpringBoot提供了啟動(dòng)異常分析接口FailureAnalyzer,該接口位于org.springframework.boot.diagnosticspackage內(nèi)。內(nèi)部?jī)H提供一個(gè)分析的方法,源碼如下所示:
@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);
}
該接口會(huì)把遇到的異常對(duì)象實(shí)例Throwable failure交付給實(shí)現(xiàn)類,實(shí)現(xiàn)類進(jìn)行自定義處理。
AbstractFailureAnalyzer
AbstractFailureAnalyzer是FailureAnalyzer的基礎(chǔ)實(shí)現(xiàn)抽象類,實(shí)現(xiàn)了FailureAnalyzer定義的analyze(Throwable failure)方法,并提供了一個(gè)指定異常類型的抽象方法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;
}
}
通過(guò)AbstractFailureAnalyzer源碼我們可以看到,它在實(shí)現(xiàn)于FailureAnalyzer的接口方法內(nèi)進(jìn)行了特殊處理,根據(jù)getCauseType()方法獲取當(dāng)前類定義的第一個(gè)泛型類型,也就是我們需要分析的指定異常類型。
獲取泛型異常類型后根據(jù)方法findCause判斷Throwable是否與泛型異常類型匹配,如果匹配直接返回給SpringBoot進(jìn)行注冊(cè)處理。
SpringBoot提供的分析實(shí)現(xiàn)
SpringBoot內(nèi)部通過(guò)實(shí)現(xiàn)AbstractFailureAnalyzer抽象類定義了一系列的針對(duì)性異常類型的啟動(dòng)分析,如下圖所示:
指定異常分析
SpringBoot內(nèi)部提供的啟動(dòng)異常分析都是指定具體的異常類型實(shí)現(xiàn)的,最常見(jiàn)的一個(gè)錯(cuò)誤就是端口號(hào)被占用(PortInUseException),雖然SpringBoot內(nèi)部提供一個(gè)這個(gè)異常的啟動(dòng)分析,我們也是可以進(jìn)行替換這一異常分析的,我們只需要?jiǎng)?chuàng)建PortInUseException異常的AbstractFailureAnalyzer,并且實(shí)現(xiàn)類注冊(cè)給SpringBoot即可,實(shí)現(xiàn)自定義如下所示:
/**
* 端口號(hào)被占用{@link PortInUseException}異常啟動(dòng)分析
*
* @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("端口號(hào):" cause.getPort() "被占用", "PortInUseException", rootFailure);
}
}
注冊(cè)啟動(dòng)異常分析
在上面我們只是編寫了指定異常啟動(dòng)分析,我們接下來(lái)需要讓它生效,這個(gè)生效方式比較特殊,類似于自定義SpringBoot Starter AutoConfiguration的形式,我們需要在META-INF/spring.factories文件內(nèi)進(jìn)行定義,如下所示:
org.springframework.boot.diagnostics.FailureAnalyzer=\ org.minbox.chapter.springboot.failure.analyzer.PortInUseFailureAnalyzer
那我們?yōu)槭裁葱枰褂眠@種方式定義呢?
項(xiàng)目啟動(dòng)遇到的異常順序不能確定,很可能在Spring IOC并未執(zhí)行初始化之前就出現(xiàn)了異常,我們不能通過(guò)@Component注解的形式使其生效,所以SpringBoot提供了通過(guò)spring.factories配置文件的方式定義。
啟動(dòng)異常分析繼承關(guān)系
自定義的運(yùn)行異常一般都是繼承自RuntimeException,如果我們定義一個(gè)RuntimeException的異常啟動(dòng)分析實(shí)例會(huì)是什么效果呢?
/**
* 項(xiàng)目啟動(dòng)運(yùn)行時(shí)異常{@link RuntimeException}統(tǒng)一啟動(dòng)分析
*
* @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("遇到運(yùn)行時(shí)異常", cause);
return new FailureAnalysis(cause.getMessage(), "error", rootFailure);
}
}
將該類也一并注冊(cè)到spring.factories文件內(nèi),如下所示:
org.springframework.boot.diagnostics.FailureAnalyzer=\ org.minbox.chapter.springboot.failure.analyzer.PortInUseFailureAnalyzer,\ org.minbox.chapter.springboot.failure.analyzer.ProjectBootUnifiedFailureAnalyzer
運(yùn)行項(xiàng)目并測(cè)試端口號(hào)被占用異常我們會(huì)發(fā)現(xiàn),并沒(méi)有執(zhí)行ProjectBootUnifiedFailureAnalyzer內(nèi)的analyze方法,而是繼續(xù)執(zhí)行了PortInUseFailureAnalyzer類內(nèi)的方法。
那我們將PortInUseFailureAnalyzer這個(gè)啟動(dòng)分析從spring.factories文件內(nèi)暫時(shí)刪除掉,再來(lái)運(yùn)行項(xiàng)目我們會(huì)發(fā)現(xiàn)這時(shí)卻是會(huì)執(zhí)行ProjectBootUnifiedFailureAnalyzer類內(nèi)分析方法。
總結(jié)
根據(jù)本章我們了解了SpringBoot提供的啟動(dòng)異常分析接口以及基本抽象實(shí)現(xiàn)類的運(yùn)作原理,而且啟動(dòng)異常分析存在分析泛型異常類的上下級(jí)繼承關(guān)系,異常子類的啟動(dòng)分析會(huì)覆蓋掉異常父類的啟動(dòng)分析,如果你想包含全部異常的啟動(dòng)分析可以嘗試使用Exception作為AbstractFailureAnalyzer的泛型參數(shù)。
到此這篇關(guān)于SpringBoot打印詳細(xì)啟動(dòng)異常信息的文章就介紹到這了,更多相關(guān)SpringBoot打印啟動(dòng)異常信息內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
聊聊springboot靜態(tài)資源加載的規(guī)則
這篇文章主要介紹了springboot靜態(tài)資源加載的規(guī)則,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-12-12
Mybatis select記錄封裝的實(shí)現(xiàn)
這篇文章主要介紹了Mybatis select記錄封裝的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-10-10
JDK1.8中ConcurrentHashMap中computeIfAbsent死循環(huán)bug問(wèn)題
這篇文章主要介紹了JDK1.8中ConcurrentHashMap中computeIfAbsent死循環(huán)bug,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-08-08
web 容器的設(shè)計(jì)如何實(shí)現(xiàn)
這篇文章主要介紹了web 容器的設(shè)計(jì)如何實(shí)現(xiàn)的相關(guān)資料,本文旨在介紹如何設(shè)計(jì)一個(gè)web容器,只探討實(shí)現(xiàn)的思路,并不涉及過(guò)多的具體實(shí)現(xiàn)。把它分解劃分成若干模塊和組件,每個(gè)組件模塊負(fù)責(zé)不同的功能,需要的朋友可以參考下2016-12-12
Maven重復(fù)依賴問(wèn)題解決(同一個(gè)jar多個(gè)版本)
本文主要介紹了Maven重復(fù)依賴問(wèn)題解決(同一個(gè)jar多個(gè)版本),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2023-06-06
SpringBoot+MyBatis整合ClickHouse實(shí)踐記錄
本文介紹了如何使用SpringBoot、MyBatis和ClickHouse整合,包括添加依賴、配置數(shù)據(jù)源、創(chuàng)建實(shí)體類、Mapper接口、服務(wù)層和控制器的步驟,通過(guò)這些步驟,可以使Java應(yīng)用程序高效地與ClickHouse數(shù)據(jù)庫(kù)進(jìn)行交互,感興趣的朋友跟隨小編一起看看吧2024-12-12
Java-URLDecoder、URLEncoder使用及說(shuō)明
本文介紹了Java中URLDecoder和URLEncoder類的使用方法,包括編碼和解碼規(guī)則、推薦的編碼方案、解碼器處理非法字符的方法以及URL編碼和解碼的示例2024-12-12
MyBatis處理mysql主鍵自動(dòng)增長(zhǎng)出現(xiàn)的不連續(xù)問(wèn)題解決
本文主要介紹了MyBatis處理mysql主鍵自動(dòng)增長(zhǎng)出現(xiàn)的不連續(xù)問(wèn)題解決,文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-09-09

