springboot源码-诊断分析器模块

springboot诊断分析模块

  • 诊断分析模块简介
    • 工作流程
    • 源码分析
        • 分析入口类
        • 分析器
        • 报告器
    • 总结

诊断分析模块简介

  1. springboot在启动过程中,会对启动失败的原因及异常进行诊断,并打印报告

工作流程

  1. 初始化阶段:加载springboot内置配置的分析器
  2. 准备阶段:设置bean工厂/环境配置
  3. 分析阶段:遍历调用分析器,只要有分析结果返回
  4. 报告阶段:将分析结果进行整理格式化,方便用户解读

源码分析

  1. 诊断分析模块主要分为:分析器、报告呈现

分析入口类

  1. 入口类:FailureAnalyzers
  2. 构造器
public FailureAnalyzers(ConfigurableApplicationContext context) {
	this(context, null);
}

FailureAnalyzers(ConfigurableApplicationContext context, ClassLoader classLoader) {
	Assert.notNull(context, "Context must not be null");
	this.classLoader = (classLoader == null ? context.getClassLoader() : classLoader);
	// 初始化分析器
	this.analyzers = loadFailureAnalyzers(this.classLoader);
	prepareFailureAnalyzers(this.analyzers, context);
}

// 从spring.factory文件中读取分析器
private List loadFailureAnalyzers(ClassLoader classLoader) {
	List analyzerNames = SpringFactoriesLoader
			.loadFactoryNames(FailureAnalyzer.class, classLoader);
	List 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("Failed to load " + analyzerName, ex);
		}
	}
	AnnotationAwareOrderComparator.sort(analyzers);
	return analyzers;
}
  1. 分析报告核心方法
public boolean analyzeAndReport(Throwable failure) {	
	// 先分析
	FailureAnalysis analysis = analyze(failure, this.analyzers);
	// 再生成报告
	return report(analysis, this.classLoader);
}

private FailureAnalysis analyze(Throwable failure, List analyzers) {
	// 遍历调用每个分析器分析方法
	for (FailureAnalyzer analyzer : analyzers) {
		try {
			FailureAnalysis analysis = analyzer.analyze(failure);
			if (analysis != null) {
				return analysis;
			}
		}
		catch (Throwable ex) {
			logger.debug("FailureAnalyzer " + analyzer + " failed", ex);
		}
	}
	return null;
}

private boolean report(FailureAnalysis analysis, ClassLoader classLoader) {
	// 从spring.factory文件中读取报告器
	List reporters = SpringFactoriesLoader
			.loadFactories(FailureAnalysisReporter.class, classLoader);
	if (analysis == null || reporters.isEmpty()) {
		return false;
	}
	// 遍历调用报告接口,生成报告
	for (FailureAnalysisReporter reporter : reporters) {
		reporter.report(analysis);
	}
	return true;
}

分析器

  1. 分析接口:FailureAnalyzer
  2. 抽象类:AbstractFailureAnalyzer->analyze(Throwable failure)
public FailureAnalysis analyze(Throwable failure) {
        // 主要是判断异常实例的类型,然后调用对应的分析器进行分析
	T cause = findCause(failure, getCauseType());
	if (cause != null) {
		return analyze(failure, cause);
	}
	return null;
}
protected final  E findCause(Throwable failure, Class type) {
	// 循环判断,是否是指定类型实例
	while (failure != null) {
		if (type.isInstance(failure)) {
			return (E) failure;
		}
		failure = failure.getCause();
	}
	return null;
}
  1. 具体实现类:PortInUseFailureAnalyzer(其中的一个实现类)
class PortInUseFailureAnalyzer extends AbstractFailureAnalyzer {

	@Override
	protected FailureAnalysis analyze(Throwable rootFailure, PortInUseException cause) {
		// 对异常信息进行说明,包装成FailureAnalysis对象返回
		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);
	}
}

报告器

  1. 报告接口:FailureAnalysisReporter
  2. 核心方法:void report(FailureAnalysis analysis); // 对分析结果进行报告呈现
  3. 具体实现类:LoggingFailureAnalysisReporter,主要进行日志打印
public final class LoggingFailureAnalysisReporter implements FailureAnalysisReporter {

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

	@Override
	public void report(FailureAnalysis failureAnalysis) {
		// debug模式下打印堆栈信息
		if (logger.isDebugEnabled()) {
			logger.debug("Application failed to start due to an exception",
					failureAnalysis.getCause());
		}
		// error模式下打印自定义错误信息
		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();
	}

}

总结

  1. 虽然该模块比较简单,但很有指导意义,将异常处理专门封装成一个模块,易于扩展,易于理解
  2. 使用了模版方法模式,抽象类AbstractFailureAnalyzer定义了基本流程,子类去实现,扩展性较好
  3. 功能模块划分清晰:将整个流程分为分析和报告两个大的阶段,耦合度低

你可能感兴趣的:(springboot)