SpringApplication_一个阶段结束

SpringApplication_一个阶段结束1、SpringApplication正常结束SpringBoot2.0为SpringApplication正常结束新引入了SpringApplicationRunListener的生命周期,即running(ConfigurableApplicationContext),该方法在Spring应用上下文中已准备,并且CommandLineRunner和ApplicationRunnerBean均已执行完毕。EventPublishingRunListener作为SpringApplicationRu

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全系列IDE使用 1年只要46元 售后保障 童叟无欺

1、SpringApplication正常结束

Spring Boot2.0为SpringApplication正常结束新引入了SpringApplicationRunListener的生命周期,即running(ConfigurableApplicationContext),该方法在Spring应用上下文中已准备,并且CommandLineRunner和ApplicationRunner Bean均已执行完毕。EventPublishingRunListener作为Spring ApplicationRunner 唯一内建实现,本方法中仅简单地广播ApplicationReadyEvent事件:

	@Override
	public void running(ConfigurableApplicationContext context) { 
   
		context.publishEvent(new ApplicationReadyEvent(this.application, this.args, context));
	}

不难看出当ApplicationReadyEvent事件触发后,SpringApplication的生命周期进入尾声,除非SpringApplicationRunListeners#running方法执行异常:

	public ConfigurableApplicationContext run(String... args) { 
   
		...
		try { 
   
			listeners.running(context);
		}
		catch (Throwable ex) { 
   
			handleRunFailure(context, ex, exceptionReporters, null);
			throw new IllegalStateException(ex);
		}
		return context;
	}

换言之,开发人员有两种技术手段实现完成阶段的监听,一种为实现SpringApplicationRunListeners#running方法,另一种为实现ApplicationReadyEvent事件的SpringApplicationListener。

2、SpringApplication异常结束

SpringApplication异常结束就宣告Spring Boot应用运行失败。与正常流程类似,异常流程同样作为SpringApplication生命周期的一个环节,将在SpringApplicationRunListener#failed(ConfigurableApplicationContext, Throwable)方法。

2.1、Spring Boot异常处理

	private void handleRunFailure(ConfigurableApplicationContext context, Throwable exception,
			Collection<SpringBootExceptionReporter> exceptionReporters, SpringApplicationRunListeners listeners) { 
   
		try { 
   
			try { 
   
				handleExitCode(context, exception);
				if (listeners != null) { 
   
					listeners.failed(context, exception);
				}
			}
			finally { 
   
				reportFailure(exceptionReporters, exception);
				if (context != null) { 
   
					context.close();
				}
			}
		}
		catch (Exception ex) { 
   
			logger.warn("Unable to close ApplicationContext", ex);
		}
		ReflectionUtils.rethrowRuntimeException(exception);
	}

Spring Boot异常处理主要包含两部分:一是退出码处理,二是异常报告。退出码处理放在《Spring Boot应用退出》中讲解,这里这要分析异常报告。
在Spring Boot2.0中新增了一个SpringBootExceptionReporter接口,用于支持SpringApplication启动错误的自定义报告的回调接口。

public interface SpringBootExceptionReporter { 
   

	boolean reportException(Throwable failure);

}

由于SpringBootExceptionReporter 集合在初始化过程中,明确地执行了getSpringFactoriesInstances(SpringBootExceptionReporter.class,new Class[] { ConfigurableApplicationContext.class }, context);语句,所以当自定义SpringBootExceptionReporter 时,必须用一个ConfigurableApplicationContext参数声明一个公共构造函数,比如Spring Boot2.x内建唯一实现FailureAnalyzers:

final class FailureAnalyzers implements SpringBootExceptionReporter { 
   

	private static final Log logger = LogFactory.getLog(FailureAnalyzers.class);

	private final ClassLoader classLoader;

	private final List<FailureAnalyzer> analyzers;

	FailureAnalyzers(ConfigurableApplicationContext context) { 
   
		this(context, null);
	}

	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 是FailureAnalyzer的组合类,在其构造阶段通过Spring工厂加载机制初始化并排序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;
}
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列表作为FailureAnalyzers#(Throwable, List<FailureAnalyzer>)方法的参数,随着SpringApplication#(Collection<SpringBootExceptionReporter>, Throwable)方法调用执行:

	@Override
public boolean reportException(Throwable failure) { 

FailureAnalysis analysis = analyze(failure, this.analyzers);
return report(analysis, this.classLoader);
}
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;
}
private boolean report(FailureAnalysis analysis, ClassLoader classLoader) { 

List<FailureAnalysisReporter> reporters = SpringFactoriesLoader.loadFactories(FailureAnalysisReporter.class,
classLoader);
if (analysis == null || reporters.isEmpty()) { 

return false;
}
for (FailureAnalysisReporter reporter : reporters) { 

reporter.report(analysis);
}
return true;
}

不难看出FailureAnalyzer仅分析故障,而故障报告则由FailureAnalysisReporter 对象负责。

2.2、错误分析报告器——FailureAnalysisReporter

同样地FailureAnalysisReporter也由Spring工厂加载机制初始化并排序。在Spring Boot框架中仅存在一个内建FailureAnalysisReporter的实现LoggingFailureAnalysisReporter。

public final class LoggingFailureAnalysisReporter implements FailureAnalysisReporter { 

private static final Log logger = LogFactory.getLog(LoggingFailureAnalysisReporter.class);
@Override
public void report(FailureAnalysis failureAnalysis) { 

if (logger.isDebugEnabled()) { 

logger.debug("Application failed to start due to an exception", failureAnalysis.getCause());
}
if (logger.isErrorEnabled()) { 

logger.error(buildMessage(failureAnalysis));
}
}
private String buildMessage(FailureAnalysis failureAnalysis) { 

StringBuilder builder = new StringBuilder();
builder.append(String.format("%n%n"));
builder.append(String.format("***************************%n"));
builder.append(String.format("APPLICATION FAILED TO START%n"));
builder.append(String.format("***************************%n%n"));
builder.append(String.format("Description:%n%n"));
builder.append(String.format("%s%n", failureAnalysis.getDescription()));
if (StringUtils.hasText(failureAnalysis.getAction())) { 

builder.append(String.format("%nAction:%n%n"));
builder.append(String.format("%s%n", failureAnalysis.getAction()));
}
return builder.toString();
}
}

与FailureAnalysisReporter不同的是,FailureAnalyzer的内建实现相当丰富,下面是org.springframework.boot:spring-boot-autoconfigure:2.3.0中的META-INF/spring.factories:

# Failure analyzers
org.springframework.boot.diagnostics.FailureAnalyzer=\
org.springframework.boot.autoconfigure.diagnostics.analyzer.NoSuchBeanDefinitionFailureAnalyzer,\
org.springframework.boot.autoconfigure.flyway.FlywayMigrationScriptMissingFailureAnalyzer,\
org.springframework.boot.autoconfigure.jdbc.DataSourceBeanCreationFailureAnalyzer,\
org.springframework.boot.autoconfigure.jdbc.HikariDriverConfigurationFailureAnalyzer,\
org.springframework.boot.autoconfigure.session.NonUniqueSessionRepositoryFailureAnalyzer

其中NoSuchBeanDefinitionFailureAnalyzer和DataSourceBeanCreationFailureAnalyzer在Spring Boot中经常出现。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/195760.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

  • Android startActivityForResult用法

    Android startActivityForResult用法一、介绍当我们在第一个Activity打开第二个Activity时,第二个Activity关闭并想返回数据给第一个Activity时,我们就可以使用startActivityForResult进行传值。用到的几个方法介绍:1.startActivityForResult(Intentintent,intrequestCode)requestCode:如果>=…

  • 树莓派3b+串口配置

    树莓派3b+串口配置前言树莓派从大的方向来说一共出了3代,每一代的CPU外设基本相同,但内核不同,外设里面一共包含两个串口,一个称之为硬件串口(/dev/ttyAMA0),一个称之为mini串口(/dev/ttyS0)。硬件串口由硬件实现,有单独的波特率时钟源,性能高、可靠,mini串口性能低,功能也简单,并且没有波特率专用的时钟源而是由CPU内核时钟提供,因此mini串口有个致命的弱点是:波特率受到内核时钟的影响…

  • JavaScript 数组排序

    JavaScript 数组排序JavaScript数组排序1、reverse方法2、sort方法1、reverse方法reverse方法会将数组内的元素反序排序。如:letarr=[1,2,3,4,5,6];arr.reverse();//arr=[6,5,4,3,2,1]2、sort方法sort方法默认会将元素当成字符串相互对比,也可以传入自己写的比较函数来决定排序顺序。如:letarr=[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19

  • SPSS学习笔记(五)卡方检验

    SPSS学习笔记(五)卡方检验和“SPSS学习笔记”的其他方法不同,卡方检验​​​​​​​是针对计数资料的目录一、卡方检验、Fisher精确检验(2*2)分析操作结果及分析二、卡方检验(R×C)分析操作结果及分析三、配对卡方检验分析操作结果及分析一、卡方检验、Fisher精确检验(2*2)分析:案例:该医生招募了100名研究对象,按照吸烟状态分为两组,其中吸烟者52人,不吸烟者48人,探讨吸烟与阿尔兹海默症之间的关联性需要先满足4项假设:假设1:存在两个二分类变量,

    2022年10月19日
  • Java中利用DatagramPacket与DatagramSocket进行通讯的示例

    Java中利用DatagramPacket与DatagramSocket进行通讯的示例对以下demo进行了扩展,增了消息循环和等待。 Java中的DatagramPacket与DatagramSocket的初步扩展的代码如下:1.接收端工程代码:由于接收端的控制台log会被发送端的log冲掉,所以把log写到文件中。packagecom.ameyume.receiver;importjava.io.File;importjava.io.FileNotFoundExcep

  • tomcat打印日志乱码,入库数据正常_tomcat输出日志乱码

    tomcat打印日志乱码,入库数据正常_tomcat输出日志乱码Tomcat后台日志乱码问题文章目录Tomcat后台日志乱码问题一、找到乱码原因二、Tomcat端乱码处理三、IDEA端设置小结一、找到乱码原因  基本上我们安装的windows系统本地语言都是中文,用的是GBK编码,而我们IDEA和Tomcat日志选择的是utf8编码,因此编码方式不一致造成了我们的中文乱码问题。二、Tomcat端乱码处理  既然原因已经找到了,接着就是解决问题了,分别设置IDEA和Tomcat的编码就ok了。先对Tomcat进行处理,如下:  1.找到Tomcat的安装目录

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号