您好,登錄后才能下訂單哦!
本篇文章為大家展示了怎么在SpringBoot中自定義FailureAnalyzer,內容簡明扼要并且容易理解,絕對能使你眼前一亮,通過這篇文章的詳細介紹希望你能有所收獲。
1.1 創建自己的 FailureAnalyzer
FailureAnalyzer是一種在啟動時攔截 exception 并將其轉換為 human-readable 消息的好方法,包含在故障分析中。 Spring Boot 為 application context 相關的 exceptions,JSR-303 驗證等提供了這樣的分析器。實際上很容易創建自己的。
AbstractFailureAnalyzer是FailureAnalyzer的方便擴展,它檢查 exception 中是否存在指定的 exception 類型來處理。你可以從中擴展,這樣你的 implementation 只有在它實際存在時才有機會處理 exception。如果由于某種原因你無法處理 exception,return null給另一個 implementation 一個處理 exception 的機會。
FailureAnalyzer __mplement 將在META-INF/spring.factories中注冊:以下寄存器ProjectConstraintViolationFailureAnalyzer:
org.springframework.boot.diagnostics.FailureAnalyzer=\ com.example.ProjectConstraintViolationFailureAnalyzer
1.2 排除故障 auto-configuration
Spring Boot auto-configuration 盡力'做正確的事',但有時事情會失敗,而且很難說出原因。
在 Spring Boot ApplicationContext中有一個非常有用的ConditionEvaluationReport可用。如果啟用DEBUG logging 輸出,您將看到它。如果使用spring-boot-actuator,還有一個端點,用 JSON 呈現報表。使用它來調試 application 并查看 Spring Boot 在運行時添加了哪些 features(以及哪些沒有)。
通過查看 source code 和 Javadoc 可以回答更多問題。一些經驗法則:
查找名為*AutoConfiguration的 classes 并讀取它們的源,特別是@Conditional* 注釋,以找出它們啟用的 features 和何時啟用。將--debug添加到命令 line 或 System property -Ddebug以在 console 上添加 log 在您的應用程序中做出的所有 auto-configuration 決策。在 running Actuator 應用程序中,查看autoconfig端點('/autoconfig'或 JMX 等效項)以獲取相同的信息。
查找@ConfigurationProperties(e.g. ServerProperties)的 classes 并從那里讀取可用的外部 configuration 選項。 @ConfigurationProperties有一個name屬性,作為外部 properties 的前綴,因此ServerProperties有prefix="server",其 configuration properties 是server.port,server.address等。在 running Actuator 應用程序中查看configprops端點。
尋找使用RelaxedPropertyResolver從Environment中明確地提取 configuration 值。它通常與前綴一起使用。
查找直接綁定到Environment的@Value 注釋。這不如RelaxedPropertyResolver方法靈活,但允許一些輕松的 binding,特別是 OS 環境變量(因此CAPITALS_AND_UNDERSCORES是period.separated的同義詞)。
查找@ConditionalOnExpression 注釋,以響應 SpEL 表達式打開和關閉 features,通常使用從Environment解析的占位符進行評估。
1.3 在啟動之前自定義 Environment 或 ApplicationContext
SpringApplication具有ApplicationListeners和ApplicationContextInitializers,用于將自定義應用于 context 或環境。 Spring Boot 加載了許多此類自定義項,以便在META-INF/spring.factories內部使用。注冊其他方法的方法不止一種:
通過在_運行之前調用SpringApplication上的addListeners和addInitializers方法,以編程方式為每個 application。
通過設置context.initializer.classes或context.listener.classes來聲明每個 application。
通過添加META-INF/spring.factories并打包_appar 全部用作 library 的 jar 文件來聲明所有 applications。
SpringApplication向 listeners 發送一些特殊的ApplicationEvents(甚至在創建 context 之前的一些),然后為ApplicationContext發布的 events 注冊 listeners
在使用EnvironmentPostProcessor刷新 application context 之前,還可以自定義Environment。每個 implementation 都應該在META-INF/spring.factories中注冊:
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已經準備好了 Spring Boot 默認加載的所有常用 property 源。因此,可以從環境中獲取文件的位置。此 example 在列表末尾添加custom-resource property 源,以便在任何其他常用位置中定義的 key 優先。自定義 implementation 顯然可以定義另一個 order。
雖然在@SpringBootApplication上使用@PropertySource似乎方便且容易在Environment中加載自定義資源,但我們不推薦它為 Spring Boot 在ApplicationContext刷新之前準備Environment。通過@PropertySource定義的任何 key 都將被加載太晚而不會對 auto-configuration 產生任何影響。
代碼示例
2.1 指定異常分析
SpringBoot內部提供的啟動異常分析都是指定具體的異常類型實現的,最常見的一個錯誤就是端口號被占用(PortInUseException),雖然SpringBoot內部提供一個這個異常的啟動分析,我們也是可以進行替換這一異常分析的,我們只需要創建PortInUseException異常的AbstractFailureAnalyzer,并且實現類注冊給SpringBoot即可,實現自定義如下所示
/** * @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("端口號:" + cause.getPort() + "被占用", "PortInUseException", rootFailure); } }
注冊啟動異常分析
在上面我們只是編寫了指定異常啟動分析,我們接下來需要讓它生效,這個生效方式比較特殊,類似于自定義SpringBoot Starter AutoConfiguration的形式,我們需要在META-INF/spring.factories文件內進行定義,如下所示:
org.springframework.boot.diagnostics.FailureAnalyzer=\ com.topcheer.activiti.analyzer.PortInUseFailureAnalyzer
那我們為什么需要使用這種方式定義呢?
項目啟動遇到的異常順序不能確定,很可能在Spring IOC并未執行初始化之前就出現了異常,我們不能通過@Component注解的形式使其生效,所以SpringBoot提供了通過spring.factories配置文件的方式定義。
測試:啟動2個8080端口
啟動異常分析繼承關系
自定義的運行異常一般都是繼承自RuntimeException,如果我們定義一個RuntimeException的異常啟動分析實例會是什么效果呢?
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=\ com.topcheer.activiti.analyze.PortInUseFailureAnalyzer,\ com.topcheer.activiti.analyze.ProjectBootUnifiedFailureAnalyzer
運行項目并測試端口號被占用異常我們會發現,并沒有執行ProjectBootUnifiedFailureAnalyzer內的analyze方法,而是繼續執行了PortInUseFailureAnalyzer類內的方法。
那我們將PortInUseFailureAnalyzer這個啟動分析從spring.factories文件內暫時刪除掉,再來運行項目我們會發現這時卻是會執行ProjectBootUnifiedFailureAnalyzer類內分析方法。
上述內容就是怎么在SpringBoot中自定義FailureAnalyzer,你們學到知識或技能了嗎?如果還想學到更多技能或者豐富自己的知識儲備,歡迎關注億速云行業資訊頻道。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。