zoukankan      html  css  js  c++  java
  • SpringBoot之异常报告器

    一、异常报告器介绍

    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();
    }
    

    打印输出错误信息。

  • 相关阅读:
    LVS集群的ipvsadm命令用法
    opencv学习HighGUI图形用户界面初步【1】
    openc下cv::Mat和IplImage的相互转换
    QT的creator中图示
    android的数据与访问(2)-delphi xe7如何存取我的app配置参数文件?
    win7下qt+opencv的环境配置
    android的数据与访问(1)-我的app配置参数文件放在哪儿?
    xe7android调用webservice
    android.permission
    在win7下,easyphp安装过程中MSVCR110.DLL没有被指定在WINDOWS上运行,或者它包含错误
  • 原文地址:https://www.cnblogs.com/markLogZhu/p/12517698.html
Copyright © 2011-2022 走看看