spring boot 源码解析7-SpringApplication#run第7步 - Go语言中文社区

spring boot 源码解析7-SpringApplication#run第7步


前言

SpringApplication#run第7步 只是实例化了一个FailureAnalyzers.主要是用来当出现异常时做一些分析处理.接下来我们就来分析一下

分析

  1. 实例化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步:

    1. 获得类加载器
    2. 加载FailureAnalyzer
    3. 初始化FailureAnalyzer
  2. 其中第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步:

    1. 加载/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
    2. 实例化

    3. 排序

    这里有必要介绍一下FailureAnalyzer.其类图如下:

    类图

    1. FailureAnalyzer–> 用来分析异常并且提供诊断信息,在SpringApplication中的run方法的执行过程中出错时调用:

      调用链

      其声明了一个方法–>返回针对给定的Throwable的analysis,返回null–>表明当前的FailureAnalyzer无法进行分析,如下:

      FailureAnalysis analyze(Throwable failure);
    2. 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;
      }
      1. 获得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;
        }
      2. 如果不等于null,则进行分析.抽象方法,由子类实现
      3. 返回null
    3. AbstractInjectionFailureAnalyzer–>用来对注入异常进行分析的抽象基类.其analyze实现如下:

      protected final FailureAnalysis analyze(Throwable rootFailure, T cause) {
          return analyze(rootFailure, cause, getDescription(rootFailure));
      }
      1. 根据异常获得描述信息.代码如下:

        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;
        }
        1. 获得异常堆栈中是UnsatisfiedDependencyException的异常,如果UnsatisfiedDependencyException不等于null,则调用getDescription
        2. 获得异常堆栈中是BeanInstantiationException的异常,如果不等于null,则调用getDescription
        3. 返回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();
        }
        1. 如果constructingMethod存在,则意味着是静态工厂方法初始失败,则构造描述信息
        2. 如果constructor存在,则意味是构造器失败,则构造描述信息
        3. 返回bean的类名
      2. 调用抽象方法生成FailureAnalysis
    4. 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);
      }
      1. 如果description等于null,则返回null
      2. 从异常堆栈中抽取出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

      3. 构造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());
        }
        1. 如果是工厂方法的话
        2. 返回该bean的类名
      4. 返回FailureAnalysis
    5. 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);
      }
      1. 获得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);
        }
        1. 递归异常堆栈

          1. 如果找到BeanCreationException,则构造BeanInCycle,否则,返回null
          2. 从beansInCycle中看是否存在该bean,如果不存在,则加入
          3. 跟新cycleStart
          4. 获得异常堆栈的上一层,继续处理
        2. 如果cycleStart等于-1,则返回null

        3. 返回DependencyCycle
      2. 实例化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]
        └─────┘
    6. 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);
      }
      1. 如果不是代理则返回null
      2. 返回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();
        }
    7. 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);
      }
    8. 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);
      }
    9. 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);
      }
      
    10. 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;
      }
  3. 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 实例化完毕.

版权声明:本文来源CSDN,感谢博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/qq_26000415/article/details/78915189
站方申明:本站部分内容来自社区用户分享,若涉及侵权,请联系站方删除。
  • 发表于 2020-02-25 00:59:13
  • 阅读 ( 862 )
  • 分类:

0 条评论

请先 登录 后评论

官方社群

GO教程

猜你喜欢