您好,登錄后才能下訂單哦!
微信號(hào):GitShare
微信公眾號(hào):愛(ài)折騰的稻草
如有問(wèn)題或建議,請(qǐng)?jiān)诠娞?hào)留言[1]
為幫助廣大SpringBoot用戶(hù)達(dá)到“知其然,更需知其所以然”的境界,作者將通過(guò)SpringBoot系列文章全方位對(duì)SpringBoot2.0.0.RELEASE版本深入分解剖析,讓您深刻的理解其內(nèi)部工作原理。
在SpringBoot啟動(dòng)時(shí),會(huì)查找并加載所有可用的SpringBootExceptionReporter,其源碼如下:
//7 使用SpringFactoriesLoader在應(yīng)用的classpath中查找并加載所有可用的SpringBootExceptionReporter
exceptionReporters = getSpringFactoriesInstances(
SpringBootExceptionReporter.class,
new Class[] { ConfigurableApplicationContext.class }, context);
繼續(xù)查看getSpringFactoriesInstances方法源碼:
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type,
Class<?>[] parameterTypes, Object... args) {
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
//查找并加載classpath路徑下META-INF/spring.factories中配置的SpringBootExceptionReporter的所有名稱(chēng)
Set<String> names = new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
//實(shí)例化所有的SpringBootExceptionReporter
List<T> instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
//排序
AnnotationAwareOrderComparator.sort(instances);
//返回結(jié)果
return instances;
}
代碼來(lái)看不難,也是通過(guò)Spring的Factories機(jī)制來(lái)加載,之前的文章中已經(jīng)詳細(xì)講解過(guò)其過(guò)程。
@FunctionalInterface
public interface SpringBootExceptionReporter {
/**
* 向用戶(hù)報(bào)告啟動(dòng)失敗。
*/
boolean reportException(Throwable failure);
}
SpringBootExceptionReporter是一個(gè)回調(diào)接口,用于支持對(duì)SpringApplication啟動(dòng)錯(cuò)誤的自定義報(bào)告。
里面就一個(gè)報(bào)告啟動(dòng)失敗的方法。
其實(shí)現(xiàn)類(lèi):org.springframework.boot.diagnostics.FailureAnalyzers
用于觸發(fā)從spring.factories加載的FailureAnalyzer和FailureAnalysisReporter實(shí)例。
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);
}
獲取類(lèi)加載器
加載并實(shí)例化所有的FailureAnalyzer
通過(guò)Spring的Factories機(jī)制來(lái)查找和加載所有的FailureAnalyzer,
加載/META/spring.factories 中的org.springframework.boot.diagnostics.FailureAnalyzer配置如下:
# Failure Analyzers
org.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
準(zhǔn)備所有的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());
}
}
準(zhǔn)備階段:根據(jù)FailureAnalyzer的類(lèi)型,設(shè)置其BeanFactory或者Environment屬性值。
@FunctionalInterface
public interface FailureAnalyzer {
/**
* 返回給定故障的分析,如果不無(wú)法分析,則返回null。
*/
FailureAnalysis analyze(Throwable failure);
}
用于分析故障并提供可以顯示給用戶(hù)的診斷信息。
FailureAnalyzer的抽象基類(lèi),是個(gè)泛型類(lèi),泛型參數(shù)為T(mén)hrowable的子類(lèi).其實(shí)現(xiàn)了analyze方法,源碼如下:
@Override
public FailureAnalysis analyze(Throwable failure) {
// 1. 獲得failure中的異常堆棧中是type類(lèi)型的異常
T cause = findCause(failure, getCauseType());
if (cause != null) {
// 2. 如果不等于null,則進(jìn)行分析
return analyze(failure, cause);
}
// 3. 無(wú)法分析,則返回null
return null;
}
獲得failure中的異常堆棧中是type類(lèi)型的異常。
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的具體實(shí)現(xiàn)
3.1、AbstractInjectionFailureAnalyzer:用來(lái)對(duì)注入異常進(jìn)行分析的抽象基類(lèi)。
3.2、BeanCurrentlyInCreationFailureAnalyzer:針對(duì)BeanCurrentlyInCreationException.對(duì)BeanCurrentlyInCreationException(循環(huán)依賴(lài))進(jìn)行分析。
3.3、BeanNotOfRequiredTypeFailureAnalyzer:針對(duì)BeanNotOfRequiredTypeException異常進(jìn)行分析。
3.4、BindFailureAnalyzer:針對(duì)BindException異常進(jìn)行分析。
3.5、BindValidationFailureAnalyzer :針對(duì)BindValidationException或者BindException異常進(jìn)行分析。
3.6、ConnectorStartFailureAnalyzer:針對(duì)ConnectorStartFailedException(tomcat端口占用時(shí)拋出)異常進(jìn)行分析。
3.7、DataSourceBeanCreationFailureAnalyzer:針對(duì)DataSourceBeanCreationException異常進(jìn)行分析。
3.8、HikariDriverConfigurationFailureAnalyzer:它對(duì)使用不支持的“dataSourceClassName”屬性導(dǎo)致的Hikari配置失敗進(jìn)行分析。
3.9、InvalidConfigurationPropertyNameFailureAnalyzer:針對(duì)InvalidConfigurationPropertyNameException異常進(jìn)行分析。
3.10、InvalidConfigurationPropertyValueFailureAnalyzer:針對(duì)InvalidConfigurationPropertyValueException異常進(jìn)行分析。
3.11、NoUniqueBeanDefinitionFailureAnalyzer:針對(duì)NoUniqueBeanDefinitionException異常進(jìn)行分析,且實(shí)現(xiàn)了BeanFactoryAware接口。
3.12、PortInUseFailureAnalyzer:針對(duì)PortInUseException(jetty,undertow 容器啟動(dòng)時(shí)端口占用時(shí)拋出)異常進(jìn)行分析。
3.13、UnboundConfigurationPropertyFailureAnalyzer:針對(duì)BindException異常進(jìn)行分析。
3.14、ValidationExceptionFailureAnalyzer:泛型參數(shù)為ValidationException(當(dāng)使用validation相關(guān)的注解,但是沒(méi)有加入相關(guān)實(shí)現(xiàn)時(shí)觸發(fā),一般不容易觸發(fā),因?yàn)橐坏┘尤雜pring-boot-starter-web依賴(lài),就會(huì)加入hibernate-validator)。
@FunctionalInterface
public interface FailureAnalysisReporter {
/**
* 將失敗結(jié)果(failureAnalysis)報(bào)告給用戶(hù)
*/
void report(FailureAnalysis analysis);
}
失敗結(jié)果報(bào)告接口,將失敗結(jié)果信息報(bào)告給用戶(hù)
其實(shí)現(xiàn)類(lèi):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();
}
}
通過(guò)日志的方式進(jìn)行打印失敗錯(cuò)誤信息。
Spring的代碼使用了很多設(shè)計(jì)模式,所以閱讀起來(lái)總是繞來(lái)繞去,個(gè)人感覺(jué)其可讀性比較差。今天原本是想畫(huà)出異常處理機(jī)制的相關(guān)類(lèi)圖,但是發(fā)現(xiàn)這里的接口和類(lèi)的關(guān)系都比較簡(jiǎn)單,所以就偷懶。如果您通過(guò)本文講解,還不是很清晰的話(huà),您可以將其類(lèi)圖畫(huà)出來(lái),那樣會(huì)幫助您理解。
為幫助廣大SpringBoot用戶(hù)達(dá)到“知其然,更需知其所以然”的境界,作者將通過(guò)SpringBoot系列文章全方位對(duì)SpringBoot2.0.0.RELEASE版本深入分解剖析,讓您深刻的理解其內(nèi)部工作原理。
1、[SpringBoot]利用SpringBoot快速構(gòu)建并啟動(dòng)項(xiàng)目
2、[SpringBoot]詳解SpringBoot應(yīng)用的啟動(dòng)過(guò)程
3、[SpringBoot]深入淺出剖析SpringBoot的應(yīng)用類(lèi)型識(shí)別機(jī)制
4、[SpringBoot]深入淺出剖析SpringBoot中Spring Factories機(jī)制
5、[SpringBoot]詳解SpringBoot中SpringApplication的run方法的前三步
6、[SpringBoot]圖解Spring的Environment機(jī)制
7、[SpringBoot]源碼解析SpringBoot應(yīng)用Environment的構(gòu)造過(guò)程
8、[SpringBoot]源碼解析SpringBoot的Banner機(jī)制
9、[SpringBoot]圖解SpringBoot的應(yīng)用上下文機(jī)制
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀(guān)點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。