Spring Boot 老启动失败,这次再也不怕了!

Spring Boot 项目是不是经常失败,显示一大堆的错误信息,如端口重复绑定时会打印以下异常:

*************************** APPLICATION FAILED TO START *************************** Description: Embedded servlet container failed to start. Port 8080 was already in use. Action: Identify and stop the process that's listening on port 8080 or configure this application to listen on another port.

这个大家应该很熟悉了吧!

错误信息大家都能看懂,但很不友好,那么,Spring Boot 是怎么实现这样一个异常错误信息输出的呢?今天栈长分享一个 Spring Boot 启动失败的简单易懂的玩法,让新来的实习生 1 秒都能看出问题。

如果你对 Spring Boot 还不是很熟悉,或者只是会简单的使用,那还是建议你深入学习下吧,推荐这个 Spring Boot 学习仓库,欢迎 Star 关注:

https://github.com/javastacks/spring-boot-best-practice

Failure Analyzers 介绍

Spring Boot 中注册了许多 "Failure Analyzers",即 "失败分析器",Spring Boot 中的启动失败的场景都是由这些失败分析器拦截处理的。

Spring Boot 提供了 FailureAnalyzers 接口:

package org.springframework.boot.diagnostics; /** * A {@code FailureAnalyzer} is used to analyze a failure and provide diagnostic * information that can be displayed to the user. * * @author Andy Wilkinson * @since 1.4.0 */ @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); }

这个接口的目的就是: 分析启动失败异常并显示给用户有用的诊断信息。

Spring Boot 内置注册的所有失败分析器在这个文件里面:

/org/springframework/boot/spring-boot/2.3.5.RELEASE/spring-boot-2.3.5.RELEASE-sources.jar!/META-INF/spring.factories

注册的所有失败分析器列表:

# Failure Analyzers org.springframework.boot.diagnostics.FailureAnalyzer=\ org.springframework.boot.context.properties.NotConstructorBoundInjectionFailureAnalyzer,\ org.springframework.boot.diagnostics.analyzer.BeanCurrentlyInCreationFailureAnalyzer,\ org.springframework.boot.diagnostics.analyzer.BeanDefinitionOverrideFailureAnalyzer,\ org.springframework.boot.diagnostics.analyzer.BeanNotOfRequiredTypeFailureAnalyzer,\ org.springframework.boot.diagnostics.analyzer.BindFailureAnalyzer,\ org.springframework.boot.diagnostics.analyzer.BindValidationFailureAnalyzer,\ org.springframework.boot.diagnostics.analyzer.UnboundConfigurationPropertyFailureAnalyzer,\ org.springframework.boot.diagnostics.analyzer.ConnectorStartFailureAnalyzer,\ org.springframework.boot.diagnostics.analyzer.NoSuchMethodFailureAnalyzer,\ org.springframework.boot.diagnostics.analyzer.NoUniqueBeanDefinitionFailureAnalyzer,\ org.springframework.boot.diagnostics.analyzer.PortInUseFailureAnalyzer,\ org.springframework.boot.diagnostics.analyzer.ValidationExceptionFailureAnalyzer,\ org.springframework.boot.diagnostics.analyzer.InvalidConfigurationPropertyNameFailureAnalyzer,\ org.springframework.boot.diagnostics.analyzer.InvalidConfigurationPropertyValueFailureAnalyzer

再回到上面的端口重复绑定启动失败异常,就是注册了 PortInUseFailureAnalyzer 这个失败分析器,可以看到 PortInUseFailureAnalyzer 失败分析器就在注册列表里面。

再来看下 PortInUseFailureAnalyzer 的源码:

/** * A {@code FailureAnalyzer} that performs analysis of failures caused by a * {@code PortInUseException}. * * @author Andy Wilkinson */ class PortInUseFailureAnalyzer extends AbstractFailureAnalyzer<PortInUseException> { @Override protected FailureAnalysis analyze(Throwable rootFailure, PortInUseException cause) { return new FailureAnalysis("Web server failed to start. Port " + cause.getPort() + " was already in use.", "Identify and stop the process that's listening on port " + cause.getPort() + " or configure this " + "application to listen on another port.", cause); } }

只要应用启动过程上抛出了 PortInUseException 异常就会被这个失败分析器拦截并输出可读性的错误信息,现在知道绑定重复绑定错误是怎么输出的了。

自定义 Failure Analyzers

从内置的失败分析器中可以发现,所有的分析器都继承了这个抽象基类是:AbstractFailureAnalyzer,它实现了 FailureAnalyzer 接口,一般基于这个抽象基类就可以实现自定义失败分析器的扩展。

下面栈长通过两个示例带大家了解下,如何扩展或者自定义一个 FailureAnalyzer

1、重写端口失败分析器

比如说上面的PortInUseFailureAnalyzer 输出内容是英文的,不是很直观的看出,我们可以自己实现一个中文的端口失败分析器。

很简单,创建一个失败分析器继承 AbstractFailureAnalyzer 抽象类即可:

/** * 来源微信公众号:Java技术栈 */ package cn.javastack.springboot.features.analyzer; import org.springframework.boot.diagnostics.AbstractFailureAnalyzer; import org.springframework.boot.diagnostics.FailureAnalysis; import org.springframework.boot.web.server.PortInUseException; public class PortInUseFailureAnalyzer extends AbstractFailureAnalyzer<PortInUseException> { @Override protected FailureAnalysis analyze(Throwable rootFailure, PortInUseException cause) { return new FailureAnalysis("你启动的端口 " + cause.getPort() + " 被占用了.", "快检查下端口 " + cause.getPort() + " 被哪个程序占用了,或者强制杀掉进程.", cause); } }

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wssdsf.html