微信号:GitShare
微信公众号:爱折腾的稻草
如有问题或建议,请在公众号留言[1]
为帮助广大SpringBoot用户达到“知其然,更需知其所以然”的境界,作者将通过SpringBoot系列文章全方位对SpringBoot2.0.0.RELEASE版本深入分解剖析,让您深刻的理解其内部工作原理。
在SpringBoot启动时,会查找并加载所有可用的SpringBootExceptionReporter,其源码如下:
//7 使用SpringFactoriesLoader在应用的classpath中查找并加载所有可用的SpringBootExceptionReporterexceptionReporters = getSpringFactoriesInstances( SpringBootExceptionReporter.class, new Class[] { ConfigurableApplicationContext.class }, context);
继续查看getSpringFactoriesInstances方法源码:
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) { ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); //查找并加载classpath路径下META-INF/spring.factories中配置的SpringBootExceptionReporter的所有名称 Set<String> names = new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader)); //实例化所有的SpringBootExceptionReporter List<T> instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names); //排序 AnnotationAwareOrderComparator.sort(instances); //返回结果 return instances;}
代码来看不难,也是通过Spring的Factories机制来加载,之前的文章中已经详细讲解过其过程。
@FunctionalInterfacepublic interface SpringBootExceptionReporter { /** * 向用户报告启动失败。 */ boolean reportException(Throwable failure);}
SpringBootExceptionReporter是一个回调接口,用于支持对SpringApplication启动错误的自定义报告。
里面就一个报告启动失败的方法。
其实现类:org.springframework.boot.diagnostics.FailureAnalyzers
用于触发从spring.factories加载的FailureAnalyzer和FailureAnalysisReporter实例。
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);}
获取类加载器
加载并实例化所有的FailureAnalyzer
通过Spring的Factories机制来查找和加载所有的FailureAnalyzer,
加载/META/spring.factories 中的org.springframework.boot.diagnostics.FailureAnalyzer配置如下:
# Failure Analyzersorg.springframework.boot.diagnostics.FailureAnalyzer=\org.springframework.boot.diagnostics.analyzer.BeanCurrentlyInCreationFailureAnalyzer,\org.springframework.boot.diagnostics.analyzer.BeanNotOfRequiredTypeFailureAnalyzer,\org.springframework.boot.diagnostics.analyzer.BindFailureAnalyzer,\org.springframework.boot.diagnostics.analyzer.BindValidationFailureAnalyzer,\org.springframework.boot.diagnostics.analyzer.UnboundConfigurationPropertyFailureAnalyzer,\org.springframework.boot.diagnostics.analyzer.ConnectorStartFailureAnalyzer,\org.springframework.boot.diagnostics.analyzer.NoUniqueBeanDefinitionFailureAnalyzer,\org.springframework.boot.diagnostics.analyzer.PortInUseFailureAnalyzer,\org.springframework.boot.diagnostics.analyzer.ValidationExceptionFailureAnalyzer,\org.springframework.boot.diagnostics.analyzer.InvalidConfigurationPropertyNameFailureAnalyzer,\org.springframework.boot.diagnostics.analyzer.InvalidConfigurationPropertyValueFailureAnalyzer
准备所有的FailureAnalyzer
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的类型,设置其BeanFactory或者Environment属性值。
@FunctionalInterfacepublic interface FailureAnalyzer { /** * 返回给定故障的分析,如果不无法分析,则返回null。 */ FailureAnalysis analyze(Throwable failure);}
用于分析故障并提供可以显示给用户的诊断信息。
FailureAnalyzer的抽象基类,是个泛型类,泛型参数为Throwable的子类.其实现了analyze方法,源码如下:
@Overridepublic FailureAnalysis analyze(Throwable failure) { // 1. 获得failure中的异常堆栈中是type类型的异常 T cause = findCause(failure, getCauseType()); if (cause != null) { // 2. 如果不等于null,则进行分析 return analyze(failure, cause); } // 3. 无法分析,则返回null return null;}
获得failure中的异常堆栈中是type类型的异常。
protected final <E extends Throwable> E findCause(Throwable failure, Class<E> type) { while (failure != null) { if (type.isInstance(failure)) { return (E) failure; } failure = failure.getCause(); } return null;}
AbstractFailureAnalyzer的具体实现
3.1、AbstractInjectionFailureAnalyzer:用来对注入异常进行分析的抽象基类。 3.2、BeanCurrentlyInCreationFailureAnalyzer:针对BeanCurrentlyInCreationException.对BeanCurrentlyInCreationException(循环依赖)进行分析。 3.3、BeanNotOfRequiredTypeFailureAnalyzer:针对BeanNotOfRequiredTypeException异常进行分析。 3.4、BindFailureAnalyzer:针对BindException异常进行分析。 3.5、BindValidationFailureAnalyzer :针对BindValidationException或者BindException异常进行分析。3.6、ConnectorStartFailureAnalyzer:针对ConnectorStartFailedException(tomcat端口占用时抛出)异常进行分析。 3.7、DataSourceBeanCreationFailureAnalyzer:针对DataSourceBeanCreationException异常进行分析。 3.8、HikariDriverConfigurationFailureAnalyzer:它对使用不支持的“dataSourceClassName”属性导致的Hikari配置失败进行分析。 3.9、InvalidConfigurationPropertyNameFailureAnalyzer:针对InvalidConfigurationPropertyNameException异常进行分析。 3.10、InvalidConfigurationPropertyValueFailureAnalyzer:针对InvalidConfigurationPropertyValueException异常进行分析。 3.11、NoUniqueBeanDefinitionFailureAnalyzer:针对NoUniqueBeanDefinitionException异常进行分析,且实现了BeanFactoryAware接口。 3.12、PortInUseFailureAnalyzer:针对PortInUseException(jetty,undertow 容器启动时端口占用时抛出)异常进行分析。3.13、UnboundConfigurationPropertyFailureAnalyzer:针对BindException异常进行分析。 3.14、ValidationExceptionFailureAnalyzer:泛型参数为ValidationException(当使用validation相关的注解,但是没有加入相关实现时触发,一般不容易触发,因为一旦加入spring-boot-starter-web依赖,就会加入hibernate-validator)。
@FunctionalInterfacepublic interface FailureAnalysisReporter { /** * 将失败结果(failureAnalysis)报告给用户 */ void report(FailureAnalysis analysis);}
失败结果报告接口,将失败结果信息报告给用户
其实现类: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(); }}
通过日志的方式进行打印失败错误信息。
Spring的代码使用了很多设计模式,所以阅读起来总是绕来绕去,个人感觉其可读性比较差。今天原本是想画出异常处理机制的相关类图,但是发现这里的接口和类的关系都比较简单,所以就偷懒。如果您通过本文讲解,还不是很清晰的话,您可以将其类图画出来,那样会帮助您理解。
为帮助广大SpringBoot用户达到“知其然,更需知其所以然”的境界,作者将通过SpringBoot系列文章全方位对SpringBoot2.0.0.RELEASE版本深入分解剖析,让您深刻的理解其内部工作原理。
1、[SpringBoot]利用SpringBoot快速构建并启动项目
2、[SpringBoot]详解SpringBoot应用的启动过程
3、[SpringBoot]深入浅出剖析SpringBoot的应用类型识别机制
4、[SpringBoot]深入浅出剖析SpringBoot中Spring Factories机制
5、[SpringBoot]详解SpringBoot中SpringApplication的run方法的前三步
6、[SpringBoot]图解Spring的Environment机制
7、[SpringBoot]源码解析SpringBoot应用Environment的构造过程
8、[SpringBoot]源码解析SpringBoot的Banner机制
9、[SpringBoot]图解SpringBoot的应用上下文机制
亿速云「云服务器」,即开即用、新一代英特尔至强铂金CPU、三副本存储NVMe SSD云盘,价格低至29元/月。点击查看>>
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。