社区微信群开通啦,扫一扫抢先加入社区官方微信群
社区微信群
SpringApplication#run第7步 只是实例化了一个FailureAnalyzers.主要是用来当出现异常时做一些分析处理.接下来我们就来分析一下
实例化FailureAnalyzers时将之前实例化的AnnotationConfigEmbeddedWebApplicationContext 传递给了构造器.代码如下:
analyzers = new FailureAnalyzers(context);
其构造器如下:
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);
}
还是3步:
其中第2步加载FailureAnalyzer.执行如下代码:
private List<FailureAnalyzer> loadFailureAnalyzers(ClassLoader classLoader) {
List<String> analyzerNames = SpringFactoriesLoader
.loadFactoryNames(FailureAnalyzer.class, classLoader);
List<FailureAnalyzer> analyzers = new ArrayList<FailureAnalyzer>();
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;
}
3步:
加载/META/spring.factories 中的org.springframework.boot.diagnostics.FailureAnalyzer. 配置如下:
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.ConnectorStartFailureAnalyzer,
org.springframework.boot.diagnostics.analyzer.NoUniqueBeanDefinitionFailureAnalyzer,
org.springframework.boot.diagnostics.analyzer.PortInUseFailureAnalyzer,
org.springframework.boot.diagnostics.analyzer.ValidationExceptionFailureAnalyzer
实例化
这里有必要介绍一下FailureAnalyzer.其类图如下:
FailureAnalyzer–> 用来分析异常并且提供诊断信息,在SpringApplication中的run方法的执行过程中出错时调用:
其声明了一个方法–>返回针对给定的Throwable的analysis,返回null–>表明当前的FailureAnalyzer无法进行分析,如下:
FailureAnalysis analyze(Throwable failure);
AbstractFailureAnalyzer–> FailureAnalyzer的抽象基类,是个泛型类,泛型参数为Throwable的子类.其实现了analyze方法,代码如下:
public 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类型的异常.其中getCauseType–> 获得泛型参数的实际类型.实现如下:
protected Class<? extends T> getCauseType() {
return (Class<? extends T>) ResolvableType
.forClass(AbstractFailureAnalyzer.class, getClass()).resolveGeneric();
}
findCause–>获得failure中Cause是type类型的异常.实现如下:
protected final <E extends Throwable> T findCause(Throwable failure, Class<E> type) {
while (failure != null) {
if (type.isInstance(failure)) {
return (T) failure;
}
failure = failure.getCause();
}
return null;
}
AbstractInjectionFailureAnalyzer–>用来对注入异常进行分析的抽象基类.其analyze实现如下:
protected final FailureAnalysis analyze(Throwable rootFailure, T cause) {
return analyze(rootFailure, cause, getDescription(rootFailure));
}
根据异常获得描述信息.代码如下:
private String getDescription(Throwable rootFailure) {
// 1. 获得异常堆栈中是UnsatisfiedDependencyException的异常,如果UnsatisfiedDependencyException不等于null,则调用getDescription
UnsatisfiedDependencyException unsatisfiedDependency = findMostNestedCause(
rootFailure, UnsatisfiedDependencyException.class);
if (unsatisfiedDependency != null) {
return getDescription(unsatisfiedDependency);
}
// 2. 获得异常堆栈中是BeanInstantiationException的异常,如果不等于null,则调用getDescription
BeanInstantiationException beanInstantiationException = findMostNestedCause(
rootFailure, BeanInstantiationException.class);
if (beanInstantiationException != null) {
return getDescription(beanInstantiationException);
}
// 3. 返回null
return null;
}
findMostNestedCause–>获得root异常堆栈中是给定类型的异常中最深的异常.实现如下:
private <C extends Exception> C findMostNestedCause(Throwable root, Class<C> type) {
Throwable candidate = root;
C result = null;
while (candidate != null) {
if (type.isAssignableFrom(candidate.getClass())) {
result = (C) candidate;
}
candidate = candidate.getCause();
}
return result;
}
getDescription实现如下:
private String getDescription(BeanInstantiationException ex) {
// 1. 如果constructingMethod存在,则意味着是静态工厂方法初始失败
if (ex.getConstructingMethod() != null) {
return String.format("Method %s in %s", ex.getConstructingMethod().getName(),
ex.getConstructingMethod().getDeclaringClass().getName());
}
// 2. 如果constructor存在,则意味是构造器失败
if (ex.getConstructor() != null) {
return String.format("Constructor in %s", ClassUtils
.getUserClass(ex.getConstructor().getDeclaringClass()).getName());
}
// 3. 返回bean的类名
return ex.getBeanClass().getName();
}
NoUniqueBeanDefinitionFailureAnalyzer–> 其继承了AbstractInjectionFailureAnalyzer,泛型为NoUniqueBeanDefinitionException.实现了BeanFactoryAware接口.analyze方法实现如下,
protected FailureAnalysis analyze(Throwable rootFailure,
NoUniqueBeanDefinitionException cause, String description) {
// 1. 如果description等于null,则返回null
if (description == null) {
return null;
}
// 2. 从异常堆栈中抽取出bean的id,如果不存在,则返回null
String[] beanNames = extractBeanNames(cause);
if (beanNames == null) {
return null;
}
// 3. 构造description
StringBuilder message = new StringBuilder();
message.append(String.format("%s required a single bean, but %d were found:%n",
description, beanNames.length));
for (String beanName : beanNames) {
buildMessage(message, beanName);
}
// 4. 返回FailureAnalysis
return new FailureAnalysis(message.toString(),
"Consider marking one of the beans as @Primary, updating the consumer to"
+ " accept multiple beans, or using @Qualifier to identify the"
+ " bean that should be consumed",
cause);
}
从异常堆栈中抽取出bean的id,如果不存在,则返回null.代码如下:
private String[] extractBeanNames(NoUniqueBeanDefinitionException cause) {
if (cause.getMessage().indexOf("but found") > -1) {
return StringUtils.commaDelimitedListToStringArray(cause.getMessage()
.substring(cause.getMessage().lastIndexOf(":") + 1).trim());
}
return null;
}
通过字符串的方式进行截取出bean的id
构造description.代码如下:
private void buildMessage(StringBuilder message, String beanName) {
try {
BeanDefinition definition = this.beanFactory
.getMergedBeanDefinition(beanName);
message.append(getDefinitionDescription(beanName, definition));
}
catch (NoSuchBeanDefinitionException ex) {
message.append(String
.format("t- %s: a programmatically registered singleton", beanName));
}
}
调用了getDefinitionDescription,代码如下:
private String getDefinitionDescription(String beanName, BeanDefinition definition) {
// 1. 如果是工厂方法的话
if (StringUtils.hasText(definition.getFactoryMethodName())) {
return String.format("t- %s: defined by method '%s' in %s%n", beanName,
definition.getFactoryMethodName(),
definition.getResourceDescription());
}
// 2. 返回该bean的类名
return String.format("t- %s: defined in %s%n", beanName,
definition.getResourceDescription());
}
BeanCurrentlyInCreationFailureAnalyzer–>继承自AbstractFailureAnalyzer,泛型参数为BeanCurrentlyInCreationException.对BeanCurrentlyInCreationException(循环依赖)进行分析.代码如下:
protected FailureAnalysis analyze(Throwable rootFailure,
BeanCurrentlyInCreationException cause) {
// 1. 获得DependencyCycle,如果DependencyCycle等于null,则返回null.
DependencyCycle dependencyCycle = findCycle(rootFailure);
if (dependencyCycle == null) {
return null;
}
// 2. 实例化FailureAnalysis
return new FailureAnalysis(buildMessage(dependencyCycle), null, cause);
}
获得DependencyCycle,如果DependencyCycle等于null,则返回null.代码如下:
private DependencyCycle findCycle(Throwable rootFailure) {
List<BeanInCycle> beansInCycle = new ArrayList<BeanInCycle>();
Throwable candidate = rootFailure;
int cycleStart = -1;
// 1. 递归异常堆栈
while (candidate != null) {
// 1.1 如果找到BeanCreationException,则构造BeanInCycle,否则,返回null
BeanInCycle beanInCycle = BeanInCycle.get(candidate);
if (beanInCycle != null) {
// 1.2 从beansInCycle中看是否存在该bean,如果不存在,则加入
int index = beansInCycle.indexOf(beanInCycle);
if (index == -1) {
beansInCycle.add(beanInCycle);
}
// 1.3 跟新cycleStart
cycleStart = (cycleStart == -1 ? index : cycleStart);
}
// 1.4 获得异常堆栈的上一层,继续处理
candidate = candidate.getCause();
}
// 2. 如果cycleStart等于-1,则返回null
if (cycleStart == -1) {
return null;
}
// 3. 返回DependencyCycle
return new DependencyCycle(beansInCycle, cycleStart);
}
递归异常堆栈
如果cycleStart等于-1,则返回null
实例化FailureAnalysis.代码如下:
private String buildMessage(DependencyCycle dependencyCycle) {
StringBuilder message = new StringBuilder();
message.append(String.format("The dependencies of some of the beans in the "
+ "application context form a cycle:%n%n"));
List<BeanInCycle> beansInCycle = dependencyCycle.getBeansInCycle();
int cycleStart = dependencyCycle.getCycleStart();
for (int i = 0; i < beansInCycle.size(); i++) {
BeanInCycle beanInCycle = beansInCycle.get(i);
if (i == cycleStart) {
message.append(String.format("┌─────┐%n"));
}
else if (i > 0) {
String leftSide = (i < cycleStart ? " " : "↑");
message.append(String.format("%s ↓%n", leftSide));
}
String leftSide = i < cycleStart ? " " : "|";
message.append(String.format("%s %s%n", leftSide, beanInCycle));
}
message.append(String.format("└─────┘%n"));
return message.toString();
}
最终的生成的描述如下:
The dependencies of some of the beans in the application context form a cycle:
┌─────┐
| feed defined in file [/Users/hejiarui/Documents/spring-boot-source/demo/target/classes/com/example/demo/diagnostics/currently/Feed.class]
↑ ↓
| food defined in file [/Users/hejiarui/Documents/spring-boot-source/demo/target/classes/com/example/demo/diagnostics/currently/Food.class]
└─────┘
BeanNotOfRequiredTypeFailureAnalyzer–>继承自AbstractFailureAnalyzer,泛型参数为BeanNotOfRequiredTypeException,代码如下:
protected FailureAnalysis analyze(Throwable rootFailure,
BeanNotOfRequiredTypeException cause) {
// 1. 如果不是代理则返回null
if (!Proxy.isProxyClass(cause.getActualType())) {
return null;
}
// 2. 返回FailureAnalysis
return new FailureAnalysis(getDescription(cause), ACTION, cause);
}
返回FailureAnalysisl.代码如下:
private String getDescription(BeanNotOfRequiredTypeException ex) {
StringWriter description = new StringWriter();
PrintWriter printer = new PrintWriter(description);
printer.printf(
"The bean '%s' could not be injected as a '%s' because it is a "
+ "JDK dynamic proxy that implements:%n",
ex.getBeanName(), ex.getRequiredType().getName());
for (Class<?> requiredTypeInterface : ex.getRequiredType().getInterfaces()) {
printer.println("t" + requiredTypeInterface.getName());
}
return description.toString();
}
BindFailureAnalyzer–> 继承自AbstractFailureAnalyzer,泛型参数为BindException.analyze实现如下:
protected FailureAnalysis analyze(Throwable rootFailure, BindException cause) {
// 1. 如果cause中不存在错误,则返回null
if (CollectionUtils.isEmpty(cause.getAllErrors())) {
return null;
}
StringBuilder description = new StringBuilder(
String.format("Binding to target %s failed:%n", cause.getTarget()));
// 2. 遍历cause中的ObjectError
for (ObjectError error : cause.getAllErrors()) {
// 2.1 如果是FieldError则进行拼接
if (error instanceof FieldError) {
FieldError fieldError = (FieldError) error;
description.append(String.format("%n Property: %s",
cause.getObjectName() + "." + fieldError.getField()));
description.append(
String.format("%n Value: %s", fieldError.getRejectedValue()));
}
description.append(
String.format("%n Reason: %s%n", error.getDefaultMessage()));
}
// 3. 返回FailureAnalysis
return new FailureAnalysis(description.toString(),
"Update your application's configuration", cause);
}
ConnectorStartFailureAnalyzer–>继承自AbstractFailureAnalyzer,泛型参数为ConnectorStartFailedException(tomcat端口占用时抛出).analyze实现如下:
protected FailureAnalysis analyze(Throwable rootFailure,
ConnectorStartFailedException cause) {
return new FailureAnalysis(
"The Tomcat connector configured to listen on port " + cause.getPort()
+ " failed to start. The port may already be in use or the"
+ " connector may be misconfigured.",
"Verify the connector's configuration, identify and stop any process "
+ "that's listening on port " + cause.getPort()
+ ", or configure this application to listen on another port.",
cause);
}
PortInUseFailureAnalyzer–>继承自AbstractFailureAnalyzer,泛型参数为PortInUseException(jetty,undertow 容器启动时端口占用时抛出).analyze代码实现如下:
protected FailureAnalysis analyze(Throwable rootFailure, PortInUseException cause) {
return new FailureAnalysis(
"Embedded servlet container 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);
}
ValidationExceptionFailureAnalyzer–>继承自AbstractFailureAnalyzer,泛型参数为ValidationException(当使用validation相关的注解,但是没有加入相关实现时触发,一般不容易触发,因为一旦加入spring-boot-starter-web依赖,就会加入hibernate-validator), analyze代码实现如下:
protected FailureAnalysis analyze(Throwable rootFailure, ValidationException cause) {
if (cause.getMessage().startsWith(MISSING_IMPLEMENTATION_MESSAGE)) {
return new FailureAnalysis(
"The Bean Validation API is on the classpath but no implementation"
+ " could be found",
"Add an implementation, such as Hibernate Validator, to the"
+ " classpath",
cause);
}
return null;
}
FailureAnalyzers 实例化的第3步 初始化FailureAnalyzer.执行如下代码:
private void prepareFailureAnalyzers(List<FailureAnalyzer> analyzers,
ConfigurableApplicationContext context) {
for (FailureAnalyzer analyzer : analyzers) {
prepareAnalyzer(context, analyzer);
}
}
private void prepareAnalyzer(ConfigurableApplicationContext context,
FailureAnalyzer analyzer) {
if (analyzer instanceof BeanFactoryAware) {
((BeanFactoryAware) analyzer).setBeanFactory(context.getBeanFactory());
}
}
逻辑很简单,依次遍历FailureAnalyzer,如果该FailureAnalyzer实现了BeanFactoryAware接口,就为其设置BeanFactory.那么都有哪些实现了BeanFactoryAware呢? 只有一个.
NoUniqueBeanDefinitionFailureAnalyzer. 其setBeanFactory 实现如下:
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
Assert.isInstanceOf(ConfigurableBeanFactory.class, beanFactory);
this.beanFactory = (ConfigurableBeanFactory) beanFactory;
}
至此.FailureAnalyzers 实例化完毕.
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!