一、异常报告器介绍
1.1 作用
收集错误信息,用于向用户报告错误原因。
1.2 接口定义
@FunctionalInterface public interface SpringBootExceptionReporter { // 向用户报告失败信息 boolean reportException(Throwable failure); }
二、源码解析
2.1 run 初始化
public ConfigurableApplicationContext run(String... args) { ...... Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>(); try { ...... // 获取所有 SpringBootExceptionReporter 实现类 exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class, new Class[] { ConfigurableApplicationContext.class }, context); ...... } catch (Throwable ex) { handleRunFailure(context, ex, exceptionReporters, listeners); throw new IllegalStateException(ex); } try { ...... } catch (Throwable ex) { handleRunFailure(context, ex, exceptionReporters, null); throw new IllegalStateException(ex); } return context; }
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) { ClassLoader classLoader = getClassLoader(); // 获取 spring.factoryies 中类型为 SpringBootExceptionReporter 的配置。 Set<String> names = new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader)); // 实例化创建对象 List<T> instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names); AnnotationAwareOrderComparator.sort(instances); return instances; }
Spring.facories 中对 SpringBootExceptionReporter 的配置如下:
org.springframework.boot.SpringBootExceptionReporter=\ org.springframework.boot.diagnostics.FailureAnalyzers
2.2 handleRunFailure
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); }
2.2.1 查看 handleExitCode 方法:
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); } } }
2.2.2 查看 reportFailure
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); } } protected void registerLoggedException(Throwable exception) { SpringBootExceptionHandler handler = getSpringBootExceptionHandler(); if (handler != null) { // 注册异常信息 handler.registerLoggedException(exception); } }
2.2.3 查看 reporter.reportException
@Override public boolean reportException(Throwable failure) { FailureAnalysis analysis = analyze(failure, this.analyzers); return report(analysis, this.classLoader); } 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; }
2.4.4 FailureAnalyzers
最终进入 FailureAnalyzers.reportException
@Override public boolean reportException(Throwable failure) { FailureAnalysis analysis = analyze(failure, this.analyzers); return report(analysis, this.classLoader); } 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; }
进入 LoggingFailureAnalysisReporter.report 方法:
@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(); }
打印输出错误信息。
来源:https://www.cnblogs.com/markLogZhu/p/12517698.html