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 抽象类即可:

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 类的三个主要信息分别是:

public FailureAnalysis(String description, String action, Throwable cause) {
 this.description = description;
 this.action = action;
 this.cause = cause;
}

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

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

org.springframework.boot.diagnostics.FailureAnalyzer=\
cn.javastack.springboot.features.analyzer.PortInUseFailureAnalyzer

启动输出:

***************************
APPLICATION FAILED TO START
***************************

Description:

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

Action:

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

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

2、自定义失败分析器

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

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

@Bean
public CommandLineRunner commandLineRunner(){
 throw new JavastackException("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);
 }

}

添加注册:

org.springframework.boot.diagnostics.FailureAnalyzer=\
cn.javastack.springboot.features.analyzer.PortInUseFailureAnalyzer,\
cn.javastack.springboot.features.analyzer.JavastackFailureAnalyzer

启动输出:

***************************
APPLICATION FAILED TO START
***************************

Description:

Java技术栈发生异常了……

Action:

赶快去检查一下吧!

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

总结

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

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

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

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

以上就是Spring Boot 项目启动失败的解决方案的详细内容,更多关于Spring Boot 项目启动失败的资料请关注我们其它相关文章!

(0)

相关推荐

  • 详解SpringBoot配置文件启动时动态配置参数方法

    序言 当我们要同时启用多个项目而又要使用不同端口或者变换配置属性时,我们可以在配置文件中设置${变量名}的变量来获取启动时传入的参数,从而实现了动态配置参数,使启用项目更加灵活 例子 server: port: ${PORT:50101} #服务端口 spring: application: name: xc‐govern‐center #指定服务名 eureka: client: registerWithEureka: true #服务注册,是否将自己注册到Eureka服务中 fetchReg

  • 三分钟带你了解SpringBoot真正的启动引导类

    引言 SpringBoot项目中的启动类,一般都是XXApplication,例如**「StatsApplication」,「UnionApplication」**. 每个项目的启动类名称都不一样.但是它的启动类真的是XXApplication吗? **META-INF/**Manifest.mf文件 jar文件实际上是class文件的zip压缩存档.jar并不能表达应用程序的便签信息. 「META-INF/Manifest.mf文件提供存档的便签信息.」 Manifest.mf有 「Main-

  • springboot 启动时初始化数据库的步骤

    问题描述 在spring-boot启动时,希望能执行相应的sql文件来初始化数据库. 使用配置文件初始化数据库 可以在spring-boot的配置文件application.yml中设置要初始化的sql文件.这是最简单的方法,只需要添加属性就可以实现. 首先设置spring.datasource.initialization-mode=always表示任何类型数据库都进行数据库初始化,默认情况下,spring-boot会自动加载data.sql或data-${platform}.sql文件来初始

  • SpringBoot启动类@SpringBootApplication注解背后的秘密

    在用SpringBoot的项目的时候,会发现不管干什么都离不开启动类,他是程序唯一的入口,那么他究竟为我们做了什么?本篇文章主要解析@SpringBootApplication. 一.启动类 @SpringBootApplication public class Application { public static void main(String[] args) { SpringApplication.run(Application.class,args); } } 二.@SpringBoo

  • SpringBoot居然有44种应用启动器,你都知道吗

    啥是应用启动器?SpringBoot集成了spring的很多模块,比如tomcat.redis等等.你用SpringBoot搭建项目,只需要在pom.xml引入相关的依赖,和在配置文件中简单的配置就可以使用相应模块了. 非常方便,spring boot集成了哪些启动器呢? SpringBoot应用启动器基本的一共有44种,具体如下: 1)spring-boot-starter 这是Spring Boot的核心启动器,包含了自动配置.日志和YAML. 2)spring-boot-starter-a

  • Springboot之修改启动端口的两种方式(小结)

    Springboot启动的时候,端口的设定默认是8080,这肯定是不行的,我们需要自己定义端口,Springboot提供了两种方式,第一种,我们可以通过application.yml配置文件配置,第二种,可以通过代码里面指定,在开发中,建议使用修改application.yml的方式来修改端口. 代码地址 #通过yml配置文件的方式指定端口地址 https://gitee.com/yellowcong/springboot-demo/tree/master/springboot-demo2 #硬

  • 详解SpringBoot启动类的扫描注解的用法及冲突原则

    背景 SpringBoot 启动类上,配置扫描包路径有三种方式,最近看到一个应用上三种注解都用上了,代码如下: @SpringBootApplication(scanBasePackages ={"a","b"}) @ComponentScan(basePackages = {"a","b","c"}) @MapperScan({"XXX"}) public class XXApplic

  • SpringBoot启动访问localhost:8080报错404的解决操作

    1.确定本地网络是通的: 2.确定SpringBootq启动后是不报错的 3.查看是不是自己在配置文件中加入了项目路径: 如果加入了项目路径的话,直接访问localhost:8080是不会到欢迎页面的,需要加上项目路径才能访问到欢迎页面,即localhost:8080/sell 补充知识:SpringBoot的web项目启动起来无法访问,访问时还是提示无法访问该网站 有时候可能是因为你的pom中导入了太多的依赖,一些依赖之间可能存在冲突导致项目未完全启动而无法访问显示:无法访问该网站 以上这篇S

  • 解决Spring boot 嵌入的tomcat不启动问题

    此文章记录一次spring boot通过main 方法启动无法成功的问题 Unregistering JMX-exposed beans on shutdown 问题如下,因为已经解决用的别人的截图但是效果是一样的 百度了一圈都说tomcat没有配置,但实际xml有如下配置 <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-tomc

  • springboot使用CommandLineRunner解决项目启动时初始化资源的操作

    前言: 在我们实际工作中,总会遇到这样需求,在项目启动的时候需要做一些初始化的操作,比如初始化线程池,提前加载好加密证书等. 今天就给大家介绍一个 Spring Boot 神器,专门帮助大家解决项目启动初始化资源操作. 这个神器就是 CommandLineRunner,CommandLineRunner 接口的 Component 会在所有 Spring Beans 都初始化之后,SpringApplication.run() 之前执行,非常适合在应用程序启动之初进行一些数据初始化的工作. 正文

  • Spring Boot如何移除内嵌Tomcat,使用非web方式启动

    前言:当我们使用Spring Boot编写了一个批处理应用程序,该程序只是用于后台跑批数据,此时不需要内嵌的tomcat,简化启动方式使用非web方式启动项目,步骤如下: 1.修改pom.xml文件 在pom.xml文件中去除内嵌tomcat,添加servlet依赖 <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</

  • SpringBoot一个非常蛋疼的无法启动的问题解决

    今天遇到了一个非常蛋疼的问题,好好的项目,没有任何报错,但是就是启动不了 还抱一个我看不出问题的错误: java.lang.NoSuchMethodError: org.springframework.data.repository.config.AnnotationRepositoryConfigurationSource  java.lang.NoSuchMethodError: org.springframework.util.Assert.notNull 真尼玛费时间,几乎一下午就在找原

  • 详解springBoot启动时找不到或无法加载主类解决办法

    1.jar包错误 第一步:首先鼠标键右击你的项目,点击run as-->maven clean 第二步:鼠标键右击你的项目,run as--->maven install:在eclipse控制台你可以看见报错的jar包: 第三步:去maven仓库删除对应的jar,右击你的项目,maven-->update project(重新下载jar包): 第四步:重复一,二步骤,找到你的启动类,run as java application;问题解决 2.jdk报错 打开你的项目结构,找到libra

随机推荐