本Spring Boot版本是2.2.2
1、流程
1.1、 初始化流程
在run 方法中,将所有的方法都放在了try块中,而在catch 块中处理所有的异常和错误(Throwable )
(1) 创建 SpringBootExceptionReporter 实例
从spring.factories中获取 SpringBootExceptionReporter 类型的类的全类名,实例化这些类
(2)创建 FailureAnlyzer 实例
从从spring.factories中获取 FailureAnlyzer 类型的类的全类名,实例化这些类并放入 SpringBootExceptionReporter 实例的List实例变量中
1.2、调用流程
2、源码
public ConfigurableApplicationContext run(String... args) {
...
Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
...
try {
...
// 从spring.factories 文件中获取并创建所有 SpringBootExceptionReporter 类型实例
exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,
new Class[] { ConfigurableApplicationContext.class }, context);
...
}
catch (Throwable ex) {
handleRunFailure(context, ex, exceptionReporters, listeners);
throw new IllegalStateException(ex);
}
try {
listeners.running(context);
}
catch (Throwable ex) {
handleRunFailure(context, ex, exceptionReporters, null);
throw new IllegalStateException(ex);
}
return context;
}
2.1、创建 SpringBootExceptionReporter 实例
1、从spring.factories 中解析出全类名(SpringBootExceptionReporter类型的类的)
之前分析过,这里略…
2、创建这些类的实例,其中有FailureAnalyzers(目前SpringBoot中SpringBootExceptionReporter接口只有这个一个实现类),FailureAnalyzers构造方法如下:
FailureAnalyzers(ConfigurableApplicationContext context, ClassLoader classLoader) {
Assert.notNull(context, "Context must not be null");
this.classLoader = (classLoader != null) ? classLoader : context.getClassLoader();
this.analyzers = loadFailureAnalyzers(this.classLoader);
prepareFailureAnalyzers(this.analyzers, context);
}
FailureAnalyzers 构造方法做了两件事情
(2.1)解析,创建,排序 ,即从spring.factories中解析所有 FailureAnalyzer 类型的类全名,并创建这些类的实例
private List<FailureAnalyzer> loadFailureAnalyzers(ClassLoader classLoader) {
List<String> analyzerNames = SpringFactoriesLoader.loadFactoryNames(FailureAnalyzer.class, classLoader);
List<FailureAnalyzer> analyzers = new ArrayList<>();
for (String analyzerName : analyzerNames) {
try {
Constructor<?> constructor = ClassUtils.forName(analyzerName, classLoader).getDeclaredConstructor();
ReflectionUtils.makeAccessible(constructor);
analyzers.add((FailureAnalyzer) constructor.newInstance());
}
catch (Throwable ex) {
logger.trace(LogMessage.format("Failed to load %s", analyzerName), ex);
}
}
AnnotationAwareOrderComparator.sort(analyzers);
return analyzers;
}
笔者环境解析结果
analyzers = {ArrayList@3363} size = 18
0 = {BeanCurrentlyInCreationFailureAnalyzer@2918}
1 = {BeanDefinitionOverrideFailureAnalyzer@3402}
2 = {BeanNotOfRequiredTypeFailureAnalyzer@3403}
3 = {BindFailureAnalyzer@3404}
4 = {BindValidationFailureAnalyzer@3405}
5 = {UnboundConfigurationPropertyFailureAnalyzer@3406}
6 = {ConnectorStartFailureAnalyzer@3407}
7 = {NoSuchMethodFailureAnalyzer@3408}
8 = {NoUniqueBeanDefinitionFailureAnalyzer@3398}
9 = {PortInUseFailureAnalyzer@3409}
10 = {ValidationExceptionFailureAnalyzer@3410}
11 = {InvalidConfigurationPropertyNameFailureAnalyzer@3411}
12 = {InvalidConfigurationPropertyValueFailureAnalyzer@3412}
13 = {NoSuchBeanDefinitionFailureAnalyzer@3413}
14 = {FlywayMigrationScriptMissingFailureAnalyzer@3414}
15 = {DataSourceBeanCreationFailureAnalyzer@3415}
16 = {HikariDriverConfigurationFailureAnalyzer@3416}
17 = {NonUniqueSessionRepositoryFailureAnalyzer@3417}
这些类都是 FailureAnalyzer 接口的实现类,我们来看看 FailureAnalyzer 接口
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);
}
我们发现接口中只有 analyze
方法,方法返回类型是 FailureAnalysis ,FailureAnalysis 用来封装失败信息的,下面是FailureAnalysis 类的定义:
public class FailureAnalysis {
private final String description;// 错误描述
private final String action;// 处理失败的操作
private final Throwable cause;// 失败原因
}
下面是使用同一端口第二次启动应用的报错信息,大家看看 Description 和 Action 的描述感受一下
Description:
Web server failed to start. Port 8008 was already in use.
Action:
Identify and stop the process that's listening on port 8008 or configure this application to listen on another
port.
(2.2)为BeanFactoryAware 或 EnvironmentAware类型的 FailureAnalyzer 实例,注入BeanFactory 或 Environment
private void prepareFailureAnalyzers(List<FailureAnalyzer> analyzers, ConfigurableApplicationContext context) {
for (FailureAnalyzer analyzer : analyzers) {
prepareAnalyzer(context, analyzer);
}
}
private void prepareAnalyzer(ConfigurableApplicationContext context, FailureAnalyzer analyzer) {
if (analyzer instanceof BeanFactoryAware) {
((BeanFactoryAware) analyzer).setBeanFactory(context.getBeanFactory());
}
if (analyzer instanceof EnvironmentAware) {
((EnvironmentAware) analyzer).setEnvironment(context.getEnvironment());
}
}
FailureAnalyzer 类型的实例有:
1、BeanFactoryAware
NoUniqueBeanDefinitionFailureAnalyzer
NoSuchBeanDefinitionFailureAnalyzer
2、EnvironmentAware
InvalidConfigurationPropertyValueFailureAnalyzer
DataSourceBeanCreationFailureAnalyzer
2.2、处理异常
当程序发生异常时,在 catch 块中处理这个异常
private void handleRunFailure(ConfigurableApplicationContext context, Throwable exception,
Collection<SpringBootExceptionReporter> exceptionReporters, SpringApplicationRunListeners listeners) {
try {
try {
// 1、
handleExitCode(context, exception);
if (listeners != null) {
// 2、
listeners.failed(context, exception);
}
}
finally {
// 3、
reportFailure(exceptionReporters, exception);
if (context != null) {
// 4、
context.close();
}
}
}
catch (Exception ex) {
logger.warn("Unable to close ApplicationContext", ex);
}
ReflectionUtils.rethrowRuntimeException(exception);
}
发生端口占用异常时:
exception = {PortInUseException@5268} "org.springframework.boot.web.server.PortInUseException:
Port 8008 is already in use"
$assertionsDisabled = true
cause = null
CAUSE_CAPTION = "Caused by: "
detailMessage = "Port 8008 is already in use"
EMPTY_THROWABLE_ARRAY = {Throwable[0]@5295}
Exception.serialVersionUID = -3387516993124229948
NULL_CAUSE_MESSAGE = "Cannot suppress a null exception."
port = 8008
SELF_SUPPRESSION_MESSAGE = "Self-suppression not permitted"
serialVersionUID = -7034897190745766939
stackTrace = {StackTraceElement[10]@5300}
SUPPRESSED_CAPTION = "Suppressed: "
SUPPRESSED_SENTINEL = {Collections$UnmodifiableRandomAccessList@5302} size = 0
suppressedExceptions = {Collections$UnmodifiableRandomAccessList@5302} size = 0
Throwable.serialVersionUID = -3042686055658047285
UNASSIGNED_STACK = {StackTraceElement[0]@5298}
(1)、
/********** org.springframework.boot.SpringApplication ******************/
private void handleExitCode(ConfigurableApplicationContext context, Throwable exception) {
int exitCode = getExitCodeFromException(context, exception);
if (exitCode != 0) {
if (context != null) {
context.publishEvent(new ExitCodeEvent(context, exitCode));
}
SpringBootExceptionHandler handler = getSpringBootExceptionHandler();
if (handler != null) {
handler.registerExitCode(exitCode);
}
}
}
private int getExitCodeFromException(ConfigurableApplicationContext context, Throwable exception) {
int exitCode = getExitCodeFromMappedException(context, exception);
if (exitCode == 0) {
exitCode = getExitCodeFromExitCodeGeneratorException(exception);
}
return exitCode;
}
private int getExitCodeFromMappedException(ConfigurableApplicationContext context, Throwable exception) {
if (context == null || !context.isActive()) {
return 0;
}
ExitCodeGenerators generators = new ExitCodeGenerators();
Collection<ExitCodeExceptionMapper> beans // 空的
= context.getBeansOfType(ExitCodeExceptionMapper.class).values();
generators.addAll(exception, beans);// exception 就是 PortInUseException实例
return generators.getExitCode();
}
private int getExitCodeFromExitCodeGeneratorException(Throwable exception) {
if (exception == null) {
return 0;
}
if (exception instanceof ExitCodeGenerator) {
return ((ExitCodeGenerator) exception).getExitCode();
}
return getExitCodeFromExitCodeGeneratorException(exception.getCause());
}
/********** org.springframework.boot.ExitCodeGenerators ******************/
void addAll(Throwable exception, Iterable<? extends ExitCodeExceptionMapper> mappers) {
Assert.notNull(exception, "Exception must not be null");
Assert.notNull(mappers, "Mappers must not be null");
for (ExitCodeExceptionMapper mapper : mappers) {
add(exception, mapper);
}
}
void add(Throwable exception, ExitCodeExceptionMapper mapper) {
Assert.notNull(exception, "Exception must not be null");
Assert.notNull(mapper, "Mapper must not be null");
add(new MappedExitCodeGenerator(exception, mapper));
}
void add(ExitCodeGenerator generator) {
Assert.notNull(generator, "Generator must not be null");
this.generators.add(generator);
}
int getExitCode() {
int exitCode = 0;
for (ExitCodeGenerator generator : this.generators) {
try {
int value = generator.getExitCode();
if (value > 0 && value > exitCode || value < 0 && value < exitCode) {
exitCode = value;
}
}
catch (Exception ex) {
exitCode = (exitCode != 0) ? exitCode : 1;
ex.printStackTrace();
}
}
return exitCode;
}
(2)、
(3)、报告异常
private void reportFailure(Collection<SpringBootExceptionReporter> exceptionReporters, Throwable failure) {
try {
for (SpringBootExceptionReporter reporter : exceptionReporters) {
if (reporter.reportException(failure)) {
registerLoggedException(failure);
return;
}
}
}
catch (Throwable ex) {
// Continue with normal handling of the original failure
}
if (logger.isErrorEnabled()) {
logger.error("Application run failed", failure);
registerLoggedException(failure);
}
}
private FailureAnalysis analyze(Throwable failure, List<FailureAnalyzer> analyzers) {
for (FailureAnalyzer analyzer : analyzers) {
try {
FailureAnalysis analysis = analyzer.analyze(failure);
if (analysis != null) {
return analysis;
}
}
catch (Throwable ex) {
logger.debug(LogMessage.format("FailureAnalyzer %s failed", analyzer), ex);
}
}
return null;
}
protected Class<? extends T> getCauseType() {
return (Class<? extends T>) ResolvableType.forClass(AbstractFailureAnalyzer.class, getClass()).resolveGeneric();
}
(4)、