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中经常出现。

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

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

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • idea导入springboot源码

    idea导入springboot源码两天啊,导入了两天没有成功啊,网上搜了超级多的教程,没有用啊。而后我让领导帮我试试,领导从github直接下载源码包,然后通过idea的open导入,然后idea就自动下载jar包,然后,然后就好了!!!我人傻了。下载的是2.2.X,因为我本地用的是maven,所以在2.2.9.release版本之后用的都是gradle构建项目的。后来发现,是我自作聪明了。原来,maven默认配置文件在C盘,我当时装的时候移到D盘,然后导入源码的时候怎么都识别不了,目前具体原因还没有找到,但是我把maven的配置

    2022年5月23日
    63
  • java定时器配置_java定时器实现如何配置?「建议收藏」

    java定时器配置_java定时器实现如何配置?「建议收藏」定时器在一些时候会起到不可忽视的作用,本篇文章我们就来通过一些例子详细了解一下定时器的实现。例1:importjava.util.TimerTask;publicclassTimeTastextendsTimerTask…{//在这里写你要定时执行的方法publicvoidrun()…System.out.println(“HelloWorld!”);}}importj…

    2022年9月18日
    0
  • Thread.IsBackground

    Thread.IsBackground解释:  获取或设置一个值,该值指示某个线程是否为后台线程。  后台线程不会防止应用程序的进程被终止掉。        注意:主线程中创建了一个线程,线程的IsBackground默认是设置为FALSE的。主线程退出时,IsBackground=FALSE线程继续执行下去,直到线程执行结束。IsBackground=TRUE的线程才会随着主线程的退出…

    2022年10月17日
    0
  • 中心极限与大数定理律的关系_大数定理的通俗理解(辛钦、伯努利、切比雪夫大数定理)…

    中心极限与大数定理律的关系_大数定理的通俗理解(辛钦、伯努利、切比雪夫大数定理)…大数定理简单来说 指得是某个随机事件在单次试验中可能发生也可能不发生 但在大量重复实验中往往呈现出明显的规律性 即该随机事件发生的频率会向某个常数值收敛 该常数值即为该事件发生的概率 另一种表达方式为当样本数据无限大时 样本均值趋于总体均值 因为现实生活中 我们无法进行无穷多次试验 也很难估计出总体的参数 大数定律告诉我们能用频率近似代替概率 能用样本均值近似代替总体均值 很好得解决了现实问题 大

    2025年6月8日
    0
  • JAVA葵花宝典(基础版)

    JAVA葵花宝典(基础版)JAVA葵花宝典(基础版)20201209response.getWriter().write()和response.getWriter().print()的区别newObjectMapper().writeValueAsString();JSON.stringify()常量命名【idea技巧】IDEA给方法添加注释模板newJdbcTemplate(JDBCUtil.getDataSource()).queryForObject()20201212【idea快捷键】显示方法参数ctrl+p获取验证

    2022年7月7日
    35
  • 最小角回归 LARS算法包的用法以及模型参数的选择(R语言 )

    最小角回归 LARS算法包的用法以及模型参数的选择(R语言 )Lasso回归模型,是常用线性回归的模型,当模型维度较高时,Lasso算法通过求解稀疏解对模型进行变量选择。Lars算法则提供了一种快速求解该模型的方法。Lars算法的基本原理有许多其他文章可以参考,这里不过多赘述,这里主要简介如何在R中利用lars算法包求解线性回归问题以及参数的选择方法。以下的的一些用法参照lars包的帮助文件,再加上自己的使用心得。所用的示例数据diabetes是Efron…

    2022年6月26日
    25

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

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