前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Spring Boot 老启动失败,这次再也不怕了!

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

作者头像
Java技术栈
发布2021-03-09 11:05:16
8010
发布2021-03-09 11:05:16
举报
文章被收录于专栏:Java技术栈

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

代码语言:javascript
复制
***************************
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 启动失败的简单易懂的玩法。

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

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

Failure Analyzers 介绍

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

Spring Boot 提供了 FailureAnalyzers 接口:

代码语言:javascript
复制
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

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

代码语言:javascript
复制
# 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 的源码:

代码语言:javascript
复制
/**
 * 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 抽象类即可:

代码语言:javascript
复制
/**
 * 来源微信公众号: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);
   }

}

重写 analyze 方法,并返回一个 FailureAnalysis 对象,FailureAnalysis 类的三个主要信息分别是:

代码语言:javascript
复制
public FailureAnalysis(String description, String action, Throwable cause) {
   this.description = description;
   this.action = action;
   this.cause = cause;
}

即要展示的:可读性的错误描述、建议的检查修复动作、原始异常。

然后在自己的资源目录下创建 META-INF/spring.factories 文件,内容添加:

代码语言:javascript
复制
org.springframework.boot.diagnostics.FailureAnalyzer=\
cn.javastack.springboot.features.analyzer.PortInUseFailureAnalyzer

启动输出:

代码语言:javascript
复制
***************************
APPLICATION FAILED TO START
***************************

Description:

你启动的端口 8080 被占用了.

Action:

快检查下端口 8080 被哪个程序占用了,或者强制杀掉进程.

这样重新实现一下是不是要清楚多了?实习生都能看懂!

2、自定义失败分析器

下面再来自定义一个全新的失败分析器,让大家能更清楚的认识失败分析器。

我们在创建 Bean 的过程中手动抛出一个自定义的异常:

代码语言:javascript
复制
/**
 * 来源微信公众号:Java技术栈
 */
@Bean
public CommandLineRunner commandLineRunner(){
    throw new JavastackException("Java技术栈异常");
}

添加一个失败分析器拦截该异常:

代码语言:javascript
复制
/**
 * 来源微信公众号:Java技术栈
 */
package cn.javastack.springboot.features.analyzer;

import org.springframework.boot.diagnostics.AbstractFailureAnalyzer;
import org.springframework.boot.diagnostics.FailureAnalysis;

public class JavastackFailureAnalyzer extends AbstractFailureAnalyzer<JavastackException> {

   @Override
   protected FailureAnalysis analyze(Throwable rootFailure, JavastackException cause) {
      return new FailureAnalysis("Java技术栈发生异常了……",
            "赶快去检查一下吧!",
            cause);
   }

}

添加注册:

代码语言:javascript
复制
org.springframework.boot.diagnostics.FailureAnalyzer=\
cn.javastack.springboot.features.analyzer.PortInUseFailureAnalyzer,\
cn.javastack.springboot.features.analyzer.JavastackFailureAnalyzer

启动输出:

代码语言:javascript
复制
***************************
APPLICATION FAILED TO START
***************************

Description:

Java技术栈发生异常了……

Action:

赶快去检查一下吧!

如果不注册该失败分析器,这个自定义的异常就不会被内置的失败分析器拦截,就会输出大堆的异常信息,使用失败分析器能很直观的看出是什么错误及怎么修复这个错误。

总结

Spring Boot 提供的失败分析器以友好的错误信息和修复建议代替了大堆的错误异常信息,可以帮助我们更直观的定位应用启动故障,你学会了吗?

本文的所有示例源代码都已上传到了 Github:

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

欢迎大家 Star 关注,后续会不断更新。

学习更多 Spring Boot 教程,请关注公众号Java技术栈,在后台回复:boot,历史 Spring Boot 教程我都整理好了。

最后,别忘了点在看、转发哦,需要你的鼓励~

版权申明:本文系公众号 "Java技术栈" 原创,原创实属不易,转载、引用本文内容请注明出处,禁止抄袭、洗稿,请自重,尊重他人劳动成果和知识产权。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2021-03-02,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Java技术栈 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Failure Analyzers 介绍
  • 自定义 Failure Analyzers
    • 1、重写端口失败分析器
      • 2、自定义失败分析器
      • 总结
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档