Foreword
A Spring Boot application occasionally fails to start for some reason, at this time Spring Boot will friendly output a text similar to this, telling you what happened and even what action should be taken:
***************************
APPLICATION FAILED TO START
***************************
Description:
Parameter 0 of constructor in com.example.B required a bean of type 'com.example.A' that could not be found.
Action:
Consider defining a bean of type 'com.example.A' in your configuration.
How did this happen? Perhaps the first idea is that Spring Boot will construct such a complete exception and output where the problem occurs. In fact, this is not the case. Spring Boot provides a unified interface for problem analysis and diagnosis. This is the org.springframework.boot.diagnostics.FailureAnalyzer
interface.
The source code version used in this article is 2.2.2.RELEASE, if there is any discrepancy, please check whether the version is inconsistent.
Where to start
It is known that the Spring Boot project is SpringApplication#run(java.lang.String...)
started by calling . We will find that when the startup process throws an exception, it is handled like this:
catch (Throwable ex) {
handleRunFailure(context, ex, exceptionReporters, listeners);
// ...
}
Observe that the found method parameter exceptionReporters
is used to report the exception handling. Looking back to find its definition, it is found that it SpringFactoriesLoader#loadFactoryNames
loads the SpringBootExceptionReporter
implementation class defined in spring.factories in META-INF under the classpath .
There is generally only FailureAnalyzers
one implementation class, and the processing inside is also very simple: by SpringFactoriesLoader
loading into all defined FailureAnalyzer
implementations, and then preparing a little bit. When analyzing abnormalities, it is good to traverse all to FailureAnalyzer
see who can analyze the problem. After the analysis, the results of the analysis are reported, and FailureAnalysisReporter
all the implementation classes are loaded and then reported one by one. There is usually only one, that is, we see the output log in the "Preface" LoggingFailureAnalysisReporter
.
SpringFactoriesLoader is similar to Java's native SPI, which can be achieved by writing a configuration file to find a service for an interface.
Be your own
If you make your own component, you may encounter situations where you need to handle exceptions and provide recommendations to users.
We define an exception
public class WannaStopException extends RuntimeException {
}
We define a Bean that will throw an exception under certain (full) types (parts)
@Service
public class A {
public A() {
throw new WannaStopException();
}
}
We define a FailureAnalyzer
special deal with thisWannaStopException
public class StopFailureAnalyzer extends AbstractFailureAnalyzer<WannaStopException> {
@Override
protected FailureAnalysis analyze(Throwable rootFailure, WannaStopException cause) {
for (StackTraceElement stackTraceElement : cause.getStackTrace()) {
if (stackTraceElement.getClassName().equals("com.example.flowable.A")) {
return new FailureAnalysis("A想停止", "别要A了", cause);
}
}
return null;
}
}
AbstractFailureAnalyzer helps us find specific anomalies
Next we have to put StopFailureAnalyzer
it spring.factories
in and add it in resources / META-INF / spring.factories (built by ourselves)
org.springframework.boot.diagnostics.FailureAnalyzer=\
com.example.flowable.StopFailureAnalyzer
Launch this application, you can see the following output
***************************
APPLICATION FAILED TO START
***************************
Description:
A wants to stop
Action:
Don't ask for A
In addition, it is noted that it FailureAnalysisReporter
can be used to alert the development or perform some automatic repair operations (such as automatic rollback).