SpringBoot自定義FailureAnalyzer詳解
FailureAnalyzer說(shuō)明
創(chuàng)建自己的 FailureAnalyzer
FailureAnalyzer是一種在啟動(dòng)時(shí)攔截 exception 并將其轉(zhuǎn)換為 human-readable 消息的好方法,包含在故障分析中。 Spring Boot 為 application context 相關(guān)的 exceptions,JSR-303 驗(yàn)證等提供了這樣的分析器。實(shí)際上很容易創(chuàng)建自己的。
AbstractFailureAnalyzer是FailureAnalyzer的方便擴(kuò)展,它檢查 exception 中是否存在指定的 exception 類(lèi)型來(lái)處理。你可以從中擴(kuò)展,這樣你的 implementation 只有在它實(shí)際存在時(shí)才有機(jī)會(huì)處理 exception。如果由于某種原因你無(wú)法處理 exception,return null給另一個(gè) implementation 一個(gè)處理 exception 的機(jī)會(huì)。
FailureAnalyzer __mplement 將在META-INF/spring.factories中注冊(cè):以下寄存器ProjectConstraintViolationFailureAnalyzer:
org.springframework.boot.diagnostics.FailureAnalyzer=\com.example.ProjectConstraintViolationFailureAnalyzer
排除故障 auto-configuration
Spring Boot auto-configuration 盡力'做正確的事',但有時(shí)事情會(huì)失敗,而且很難說(shuō)出原因。
在 Spring Boot ApplicationContext中有一個(gè)非常有用的ConditionEvaluationReport可用。如果啟用DEBUG logging 輸出,您將看到它。如果使用spring-boot-actuator,還有一個(gè)端點(diǎn),用 JSON 呈現(xiàn)報(bào)表。使用它來(lái)調(diào)試 application 并查看 Spring Boot 在運(yùn)行時(shí)添加了哪些 features(以及哪些沒(méi)有)。
通過(guò)查看 source code 和 Javadoc 可以回答更多問(wèn)題。一些經(jīng)驗(yàn)法則:
- 查找名為*AutoConfiguration的 classes 并讀取它們的源,特別是@Conditional* 注釋,以找出它們啟用的 features 和何時(shí)啟用。將--debug添加到命令 line 或 System property -Ddebug以在 console 上添加 log 在您的應(yīng)用程序中做出的所有 auto-configuration 決策。在 running Actuator 應(yīng)用程序中,查看autoconfig端點(diǎn)('/autoconfig'或 JMX 等效項(xiàng))以獲取相同的信息。
- 查找@ConfigurationProperties(e.g. ServerProperties)的 classes 并從那里讀取可用的外部 configuration 選項(xiàng)。 @ConfigurationProperties有一個(gè)name屬性,作為外部 properties 的前綴,因此ServerProperties有prefix="server",其 configuration properties 是server.port,server.address等。在 running Actuator 應(yīng)用程序中查看configprops端點(diǎn)。
- 尋找使用RelaxedPropertyResolver從Environment中明確地提取 configuration 值。它通常與前綴一起使用。
- 查找直接綁定到Environment的@Value 注釋。這不如RelaxedPropertyResolver方法靈活,但允許一些輕松的 binding,特別是 OS 環(huán)境變量(因此CAPITALS_AND_UNDERSCORES是period.separated的同義詞)。
- 查找@ConditionalOnExpression 注釋,以響應(yīng) SpEL 表達(dá)式打開(kāi)和關(guān)閉 features,通常使用從Environment解析的占位符進(jìn)行評(píng)估。
在啟動(dòng)之前自定義 Environment 或 ApplicationContext
SpringApplication具有ApplicationListeners和ApplicationContextInitializers,用于將自定義應(yīng)用于 context 或環(huán)境。 Spring Boot 加載了許多此類(lèi)自定義項(xiàng),以便在META-INF/spring.factories內(nèi)部使用。注冊(cè)其他方法的方法不止一種:
- 通過(guò)在_運(yùn)行之前調(diào)用SpringApplication上的addListeners和addInitializers方法,以編程方式為每個(gè) application。
- 通過(guò)設(shè)置context.initializer.classes或context.listener.classes來(lái)聲明每個(gè) application。
- 通過(guò)添加META-INF/spring.factories并打包_appar 全部用作 library 的 jar 文件來(lái)聲明所有 applications。
SpringApplication向 listeners 發(fā)送一些特殊的ApplicationEvents(甚至在創(chuàng)建 context 之前的一些),然后為ApplicationContext發(fā)布的 events 注冊(cè) listeners
在使用EnvironmentPostProcessor刷新 application context 之前,還可以自定義Environment。每個(gè) implementation 都應(yīng)該在META-INF/spring.factories中注冊(cè):
org.springframework.boot.env.EnvironmentPostProcessor=com.example.YourEnvironmentPostProcessor
implementation 可以加載任意 files 并將它們添加到Environment。
例如,此 example 從 classpath 加載 YAML configuration 文件:
public class EnvironmentPostProcessorExample implements EnvironmentPostProcessor { private final YamlPropertySourceLoader loader = new YamlPropertySourceLoader(); @Override public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) { Resource path = new ClassPathResource("com/example/myapp/config.yml"); PropertySource<?> propertySource = loadYaml(path); environment.getPropertySources().addLast(propertySource); } private PropertySource<?> loadYaml(Resource path) { if (!path.exists()) { throw new IllegalArgumentException("Resource " + path + " does not exist"); } try { return this.loader.load("custom-resource", path, null); } catch (IOException ex) { throw new IllegalStateException( "Failed to load yaml configuration from " + path, ex); } } }
Environment已經(jīng)準(zhǔn)備好了 Spring Boot 默認(rèn)加載的所有常用 property 源。因此,可以從環(huán)境中獲取文件的位置。此 example 在列表末尾添加custom-resource property 源,以便在任何其他常用位置中定義的 key 優(yōu)先。自定義 implementation 顯然可以定義另一個(gè) order。
雖然在@SpringBootApplication上使用@PropertySource似乎方便且容易在Environment中加載自定義資源,但我們不推薦它為 Spring Boot 在ApplicationContext刷新之前準(zhǔn)備Environment。通過(guò)@PropertySource定義的任何 key 都將被加載太晚而不會(huì)對(duì) auto-configuration 產(chǎn)生任何影響。
代碼示例
指定異常分析
SpringBoot內(nèi)部提供的啟動(dòng)異常分析都是指定具體的異常類(lèi)型實(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)類(lèi)注冊(cè)給SpringBoot即可,實(shí)現(xiàn)自定義如下所示
/** * @author WGR * @create 2019/11/24 -- 23:00 */ 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)異常分析
在上面我們只是編寫(xiě)了指定異常啟動(dòng)分析,我們接下來(lái)需要讓它生效,這個(gè)生效方式比較特殊,類(lèi)似于自定義SpringBoot Starter AutoConfiguration的形式,我們需要在META-INF/spring.factories文件內(nèi)進(jìn)行定義,如下所示:
org.springframework.boot.diagnostics.FailureAnalyzer=\ com.topcheer.activiti.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ì)是什么效果呢?
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); } }
將該類(lèi)也一并注冊(cè)到spring.factories文件內(nèi),如下所示:
org.springframework.boot.diagnostics.FailureAnalyzer=\ com.topcheer.activiti.analyze.PortInUseFailureAnalyzer,\ com.topcheer.activiti.analyze.ProjectBootUnifiedFailureAnalyzer
運(yùn)行項(xiàng)目并測(cè)試端口號(hào)被占用異常我們會(huì)發(fā)現(xiàn),并沒(méi)有執(zhí)行ProjectBootUnifiedFailureAnalyzer內(nèi)的analyze方法,而是繼續(xù)執(zhí)行了PortInUseFailureAnalyzer類(lèi)內(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類(lèi)內(nèi)分析方法。
總結(jié)
根據(jù)本章我們了解了SpringBoot提供的啟動(dòng)異常分析接口以及基本抽象實(shí)現(xiàn)類(lèi)的運(yùn)作原理,而且啟動(dòng)異常分析存在分析泛型異常類(lèi)的上下級(jí)繼承關(guān)系,異常子類(lèi)的啟動(dòng)分析會(huì)覆蓋掉異常父類(lèi)的啟動(dòng)分析,如果你想包含全部異常的啟動(dòng)分析可以嘗試使用Exception作為AbstractFailureAnalyzer的泛型參數(shù)。
到此這篇關(guān)于SpringBoot自定義FailureAnalyzer詳解的文章就介紹到這了,更多相關(guān)自定義FailureAnalyzer內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
一文搞懂Java MD5算法的原理及實(shí)現(xiàn)
MD5信息摘要算法,一種被廣泛使用的密碼散列函數(shù),可以產(chǎn)生出一個(gè)128位(16字節(jié))的散列值(hash value),用于確保信息傳輸完整一致。本文將詳解MD5算法的原理及實(shí)現(xiàn),感興趣的可以了解一下2022-06-06springboot配置文件屬性變量引用方式${}和@@用法及區(qū)別說(shuō)明
這篇文章主要介紹了springboot配置文件屬性變量引用方式${}和@@用法及區(qū)別說(shuō)明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-03-03springboot應(yīng)用中使用過(guò)濾器的過(guò)程詳解
過(guò)濾器通常用于實(shí)現(xiàn)跨切面的功能,例如身份驗(yàn)證、日志記錄、請(qǐng)求和響應(yīng)的修改、性能監(jiān)控等,這篇文章主要介紹了springboot應(yīng)用中使用過(guò)濾器,需要的朋友可以參考下2023-06-06最新IDEA?2022基于JVM極致優(yōu)化?IDEA啟動(dòng)速度的方法
這篇文章主要介紹了IDEA?2022最新版?基于?JVM極致優(yōu)化?IDEA?啟動(dòng)速度,需要的朋友可以參考下2022-08-08Redis結(jié)合AOP與自定義注解實(shí)現(xiàn)分布式緩存流程詳解
項(xiàng)目中如果查詢數(shù)據(jù)是直接到MySQL數(shù)據(jù)庫(kù)中查詢的話,會(huì)查磁盤(pán)走IO,效率會(huì)比較低,所以現(xiàn)在一般項(xiàng)目中都會(huì)使用緩存,目的就是提高查詢數(shù)據(jù)的速度,將數(shù)據(jù)存入緩存中,也就是內(nèi)存中,這樣查詢效率大大提高2022-11-11Java 前臺(tái)加后臺(tái)精品圖書(shū)管理系統(tǒng)的實(shí)現(xiàn)
相信每一個(gè)學(xué)生學(xué)編程的時(shí)候,應(yīng)該都會(huì)寫(xiě)一個(gè)小項(xiàng)目——圖書(shū)管理系統(tǒng)。為什么這么說(shuō)呢?我認(rèn)為一個(gè)學(xué)校的氛圍很大一部分可以從圖書(shū)館的氛圍看出來(lái),而圖書(shū)管理系統(tǒng)這個(gè)不大不小的項(xiàng)目,接觸的多,也比較熟悉,不會(huì)有陌生感,能夠練手,又有些難度,所以我的小項(xiàng)目也來(lái)了2021-11-11