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

前言

这篇文章我们分析SpringApplication#run第8步.执行prepareContext方法.该方法的内容比较多.我们慢慢来.

分析

  1. SpringApplication#run 第8步执行如下代码:

    private void prepareContext(ConfigurableApplicationContext context,
            ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,
            ApplicationArguments applicationArguments, Banner printedBanner) {
        // 1. 上下文设置环境
        context.setEnvironment(environment);
        // 2. 调用postProcessApplicationContext方法设置上下文的beanNameGenerator和resourceLoader(如果SpringApplication有的话)
        postProcessApplicationContext(context);
        // 3. 拿到之前实例化SpringApplication对象的时候设置的ApplicationContextInitializer,调用它们的initialize方法,对上下文做初始化
        applyInitializers(context);
        // 4. contextPrepareds 是一个空实现 
        listeners.contextPrepared(context);
        // 5. 打印启动日志
        if (this.logStartupInfo) {
            logStartupInfo(context.getParent() == null);
            logStartupProfileInfo(context);
        }
    
        // Add boot specific singleton beans
        // 6. 日志往上下文的beanFactory中注册一个singleton的bean,bean的名字是springApplicationArguments,bean的实例是之前实例化的ApplicationArguments对象
        context.getBeanFactory().registerSingleton("springApplicationArguments",
                applicationArguments);
        // 如果之前获取的printedBanner不为空,那么往上下文的beanFactory中注册一个singleton的bean,bean的名字是springBootBanner,bean的实例就是这个printedBanner
        if (printedBanner != null) {
            context.getBeanFactory().registerSingleton("springBootBanner", printedBanner);
        }
    
        // Load the sources
        Set sources = getSources();
        Assert.notEmpty(sources, "Sources must not be empty");
        // 7. 调用load方法注册启动类的bean定义,也就是调用SpringApplication.run(Application.class, args);的类,SpringApplication的load方法内会创建BeanDefinitionLoader的对象,并调用它的load()方法
        load(context, sources.toArray(new Object[sources.size()]));
        // 8. 调用listeners的contextLoaded方法,说明上下文已经加载,该方法先找到所有的ApplicationListener,遍历这些listener,如果该listener继承了ApplicationContextAware类,那么在这一步会调用它的setApplicationContext方法,设置context
        listeners.contextLoaded(context);
    } 

    做了8件事:

    1. 为上下文设置Environment. 注意 这里传入的是 StandardServletEnvironment

    2. 调用postProcessApplicationContext方法设置上下文的beanNameGenerator和resourceLoader(如果SpringApplication有的话)

    3. 拿到之前实例化SpringApplication对象的时候设置的ApplicationContextInitializer,调用它们的initialize方法,对上下文做初始化
    4. 调用listeners#contextPrepared,该方法是一个空实现
    5. 打印启动日志
    6. 往上下文的beanFactory中注册一个singleton的bean,bean的名字是springApplicationArguments,bean的实例是之前实例化的ApplicationArguments对象,
      如果之前获取的printedBanner不为空,那么往上下文的beanFactory中注册一个singleton的bean,bean的名字是springBootBanner,bean的实例就是这个printedBanner.这里默认是SpringBootBanner.
    7. 调用load方法注册启动类的bean定义,也就是调用SpringApplication.run(Application.class, args);的类,SpringApplication的load方法内会创建BeanDefinitionLoader的对象,并调用它的load()方法
    8. 调用listeners的contextLoaded方法,说明上下文已经加载,该方法先找到所有的ApplicationListener,遍历这些listener,如果该listener继承了ApplicationContextAware类,那么在这一步会调用它的setApplicationContext方法,设置context
  2. 为上下文设置Environment 执行的是AnnotationConfigEmbeddedWebApplicationContext#setEnvironment,代码如下:

    public void setEnvironment(ConfigurableEnvironment environment) {
        super.setEnvironment(environment);
        this.reader.setEnvironment(environment);
        this.scanner.setEnvironment(environment);
    }

    3件事:

    1. 调用父类的setEnvironment方法.代码如下:

      public void setEnvironment(ConfigurableEnvironment environment) {
          this.environment = environment;
      }
    2. 为AnnotatedBeanDefinitionReader设置Environment.执行如下代码.

      public void setEnvironment(Environment environment) {
      this.conditionEvaluator = new ConditionEvaluator(this.registry,         environment, null);
      }

      实例化了ConditionEvaluator.其构造器如下:

      public ConditionEvaluator(BeanDefinitionRegistry registry, Environment environment, ResourceLoader resourceLoader) {
      this.context = new ConditionContextImpl(registry, environment, resourceLoader);
      }

      在实例化ConditionEvaluator时实例化了ConditionContextImpl.该类是ConditionContext的一个实现.是Condition使用时的上下文.其构造器如下:

      public ConditionContextImpl(BeanDefinitionRegistry registry, Environment environment, ResourceLoader resourceLoader) {
          this.registry = registry;
          this.beanFactory = deduceBeanFactory(registry);
          this.environment = (environment != null ? environment : deduceEnvironment(registry));
          this.resourceLoader = (resourceLoader != null ? resourceLoader : deduceResourceLoader(registry));
      }
      1. 设置BeanDefinitionRegistry.这里实际上持有的是AnnotationConfigEmbeddedWebApplicationContext.
      2. 设置beanFactory.执行如下代码:

        private ConfigurableListableBeanFactory deduceBeanFactory(BeanDefinitionRegistry source) {
        if (source instanceof ConfigurableListableBeanFactory) {
            return (ConfigurableListableBeanFactory) source;
        }
        if (source instanceof ConfigurableApplicationContext) {
            return (((ConfigurableApplicationContext) source).getBeanFactory());
        }
        return null;
        }

        由于AnnotationConfigEmbeddedWebApplicationContext是ConfigurableApplicationContext的子类,因此会调用getBeanFactory获得ConfigurableListableBeanFactory.代码如下:

        public final ConfigurableListableBeanFactory getBeanFactory() {
        return this.beanFactory;
        }

        返回的是DefaultListableBeanFactory.

      3. 设置environment.由于environment不为null,因此不会执行deduceEnvironment.因此直接设置为StandardServletEnvironment.

      4. 设置resourceLoader.由于传入的resourceLoader 为null,因此会执行deduceResourceLoader.代码如下;

        private ResourceLoader deduceResourceLoader(BeanDefinitionRegistry source) {
        if (source instanceof ResourceLoader) {
            return (ResourceLoader) source;
        }
        return null;
        }

        同样的,由于AnnotationConfigEmbeddedWebApplicationContext是ResourceLoader的子类,因此向上转型为ResourceLoader进行赋值.

    3. 为ClassPathBeanDefinitionScanner设置Environment.执行如下代码.

      public void setEnvironment(Environment environment) {
          Assert.notNull(environment, "Environment must not be null");
          this.environment = environment;
          this.conditionEvaluator = null;
      }
  3. SpringApplication#prepareContext 接下来执行的是 postProcessApplicationContext 方法.设置上下文的beanNameGenerator和resourceLoader(如果SpringApplication有的话).代码如下:

        protected void postProcessApplicationContext(ConfigurableApplicationContext context) {
        if (this.beanNameGenerator != null) {
            context.getBeanFactory().registerSingleton(
                    AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR,
                    this.beanNameGenerator);
        }
        if (this.resourceLoader != null) {
            if (context instanceof GenericApplicationContext) {
                ((GenericApplicationContext) context)
                        .setResourceLoader(this.resourceLoader);
            }
            if (context instanceof DefaultResourceLoader) {
                ((DefaultResourceLoader) context)
                        .setClassLoader(this.resourceLoader.getClassLoader());
            }
        }
    }

    2件事:

    1. 如果beanNameGenerator不为null的话,就向BeanFactory进行注册,bean id 为 org.springframework.context.annotation.internalConfigurationBeanNameGenerator.
    2. 如果resourceLoader不为null的话

      1. 如果context 是 GenericApplicationContext 子类的话,就为其设置ResourceLoader
      2. 如果context 是DefaultResourceLoader 子类的话,就为其设置ClassLoader
  4. 接下来执行第3步.代码如下:

        protected void applyInitializers(ConfigurableApplicationContext context) {
        // 1. 从SpringApplication类中的initializers集合获取所有的ApplicationContextInitializer
        for (ApplicationContextInitializer initializer : getInitializers()) {
            // 2. 循环调用ApplicationContextInitializer中的initialize方法
            Class requiredType = GenericTypeResolver.resolveTypeArgument(
                    initializer.getClass(), ApplicationContextInitializer.class);
            Assert.isInstanceOf(requiredType, context, "Unable to call initializer.");
            initializer.initialize(context);
        }
    }

    2件事:

    1. 从SpringApplication类中的initializers集合获取所有的ApplicationContextInitializer.将其封装为LinkedHashSet.

    2. 遍历之,调用其initialize 进行初始化.当前的initialize有如下:

      org.springframework.boot.context.config.DelegatingApplicationContextInitializer, 
      org.springframework.boot.context.ContextIdApplicationContextInitializer, 
      org.springframework.boot.context.ConfigurationWarningsApplicationContextInitializer, 
      org.springframework.boot.context.embedded.ServerPortInfoApplicationContextInitializer, 
      org.springframework.boot.autoconfigure.SharedMetadataReaderFactoryContextInitializer, 
      org.springframework.boot.autoconfigure.logging.AutoConfigurationReportLoggingInitializer

      我们分别看下其initialize 的实现.

      DelegatingApplicationContextInitializer#initialize

      代码如下:

      public void initialize(ConfigurableApplicationContext context) {
          ConfigurableEnvironment environment = context.getEnvironment();
          // 1. 通过env获取到context.initializer.classes配置的值,如果有则直接获取到具体的值并进行实例化
          List> initializerClasses = getInitializerClasses(environment);
          if (!initializerClasses.isEmpty()) {
              applyInitializerClasses(context, initializerClasses);
          }
      }

      还是3步

      1. 从context中获得ConfigurableEnvironment
      2. 调用getInitializerClasses获得通过context.initializer.classes 设置的class.

        代码如下:

        
        private static final String PROPERTY_NAME = "context.initializer.classes";
        
        private List> getInitializerClasses(ConfigurableEnvironment env) {
        String classNames = env.getProperty(PROPERTY_NAME);
        List> classes = new ArrayList>();
        if (StringUtils.hasLength(classNames)) {
        for (String className : StringUtils.tokenizeToStringArray(classNames, ",")) {
            classes.add(getInitializerClass(className));
        }
        }
        return classes;
        }

        3步:

        1. 从env获得context.initializer.classes 配置的值
        2. 如果有配置的话,就依次遍历之,如果有多个的话,用,分隔即可. 一般是没有配置的,这里是一个扩展点.
        3. 调用getInitializerClass 进行加载.代码如下:

              private Class getInitializerClass(String className) throws LinkageError {
          try {
          // 1. 进行加载
          Class initializerClass = ClassUtils.forName(className,
              ClassUtils.getDefaultClassLoader());
          // 2. 要加载的类必须是ApplicationContextInitializer 实现才行
          Assert.isAssignable(ApplicationContextInitializer.class, initializerClass);
          return initializerClass;
          }
          catch (ClassNotFoundException ex) {
          throw new ApplicationContextException(
              "Failed to load context initializer class [" + className + "]", ex);
          }
          }
      3. 如果有配置的话,就掉用applyInitializerClasses方法进行初始化. 代码如下:

        private void applyInitializerClasses(ConfigurableApplicationContext context,
        List> initializerClasses) {
        Class contextClass = context.getClass();
        List> initializers = new ArrayList>();
        for (Class initializerClass : initializerClasses) {
        initializers.add(instantiateInitializer(contextClass, initializerClass));
        }
        applyInitializers(context, initializers);
        }

        2件事.

        1. 依次遍历initializerClasses 进行初始化.
        2. 实例化完毕后调用applyInitializers,依次调用其initialize方法.代码如下:

          private void applyInitializers(ConfigurableApplicationContext context,
          List> initializers) {
          // 排序后调用具体ApplicationContextInitializer类中的initialize方法
          Collections.sort(initializers, new AnnotationAwareOrderComparator());
          for (ApplicationContextInitializer initializer : initializers) {
          initializer.initialize(context);
          }
          }

      ContextIdApplicationContextInitializer#initialize

      代码如下:

      public void initialize(ConfigurableApplicationContext applicationContext) {
      applicationContext.setId(getApplicationId(applicationContext.getEnvironment()));
      }

      3件事:

      1. 通过applicationContext 获得ConfigurableEnvironment
      2. 调用getApplicationId 生成id.代码如下

            private String getApplicationId(ConfigurableEnvironment environment) {
        String name = environment.resolvePlaceholders(this.name);
        String index = environment.resolvePlaceholders(INDEX_PATTERN);
        String profiles = StringUtils
            .arrayToCommaDelimitedString(environment.getActiveProfiles());
        if (StringUtils.hasText(profiles)) {
        name = name + ":" + profiles;
        }
        if (!"null".equals(index)) {
        name = name + ":" + index;
        }
        return name;
        }

        5件事.

        1. 获取名称。名称的取值依赖如下几个属性获取名称 spring.application.name,vcap.application.name, spring.config.name:application默认是application
        2. 获取索引.从以下几个属性中获得.

          • vcap.application.instance_index
          • spring.application.index
          • server.port
          • PORT
          • null

          默认是null

        3. 获取ActiveProfiles
        4. 如果profiles 不会null,就与name进行拼接
        5. 如果index 不为null的话,就与name进行拼接

        举例说明. 假如我配置 spring.profiles.active=test.端口号为8881,则最后生成的id为application:test:8881

      3. 对applicationContext 设置id.代码如下:

        public void setId(String id) {
            this.id = id;
        }

      ConfigurationWarningsApplicationContextInitializer#initialize

      代码如下:

      public void initialize(ConfigurableApplicationContext context) {
      context.addBeanFactoryPostProcessor(
              new ConfigurationWarningsPostProcessor(getChecks()));
      }

      向context中添加一个ConfigurationWarningsPostProcessor.

      在实例化ConfigurationWarningsPostProcessor时首先会调用getChecks获得Check[],传入到ConfigurationWarningsPostProcessor的构造器中.代码如下:

      protected Check[] getChecks() {
          return new Check[] { new ComponentScanPackageCheck() };
      }

      其返回了一个ComponentScanPackageCheck. 其初始化的代码如下:

      private static final Set<String> PROBLEM_PACKAGES;
      
      static {
          Set<String> packages = new HashSet<String>();
          packages.add("org.springframework");
          packages.add("org");
          PROBLEM_PACKAGES = Collections.unmodifiableSet(packages);
      }

      将org.springframework,org 加入到了PROBLEM_PACKAGES 中.

      ConfigurationWarningsPostProcessor 构造器如下:

      public ConfigurationWarningsPostProcessor(Check[] checks) {
          this.checks = checks;
      }

      这样 ConfigurationWarningsPostProcessor 就持有了ComponentScanPackageCheck.

    ServerPortInfoApplicationContextInitializer#initialize

    代码如下:

    public void initialize(ConfigurableApplicationContext applicationContext) {
        applicationContext.addApplicationListener(
                new ApplicationListener() {
    
                    @Override
                    public void onApplicationEvent(
                            EmbeddedServletContainerInitializedEvent event) {
                        ServerPortInfoApplicationContextInitializer.this
                                .onApplicationEvent(event);
                    }
    
                });
    }

    向applicationContext 添加一个监听.当发生EmbeddedServletContainerInitializedEvent时间时.会执行ServerPortInfoApplicationContextInitializer#onApplicationEvent方法.将server.ports添加到名为server.ports 的MapPropertySource

    SharedMetadataReaderFactoryContextInitializer#initialize

    代码如下:

    public void initialize(ConfigurableApplicationContext applicationContext) {
        applicationContext.addBeanFactoryPostProcessor(
                new CachingMetadataReaderFactoryPostProcessor());
    }

    向applicationContext 添加了一个CachingMetadataReaderFactoryPostProcessor 的BeanFactoryPostProcessor

    SharedMetadataReaderFactoryContextInitializer#initialize

    代码如下:

    public void initialize(ConfigurableApplicationContext applicationContext) {
        this.applicationContext = applicationContext;
        applicationContext.addApplicationListener(new AutoConfigurationReportListener());
        if (applicationContext instanceof GenericApplicationContext) {
            // Get the report early in case the context fails to load
            this.report = ConditionEvaluationReport
                    .get(this.applicationContext.getBeanFactory());
        }
    }

    2件事

    1. 向applicationContext添加了一个AutoConfigurationReportListener
    2. 如果applicationContext是GenericApplicationContext子类的话,就调用ConditionEvaluationReport#get生成ConditionEvaluationReport.代码如下:

          public static ConditionEvaluationReport get(
          ConfigurableListableBeanFactory beanFactory) {
      synchronized (beanFactory) {
          ConditionEvaluationReport report;
          if (beanFactory.containsSingleton(BEAN_NAME)) {
              report = beanFactory.getBean(BEAN_NAME, ConditionEvaluationReport.class);
          }
          else {
              report = new ConditionEvaluationReport();
              beanFactory.registerSingleton(BEAN_NAME, report);
          }
          locateParent(beanFactory.getParentBeanFactory(), report);
          return report;
      }
      }
      1. 首先判断是否包含autoConfigurationReport,如果有的话,直接获取即可.否则就实例化一个,然后进行注册.
      2. 调用locateParent.代码如下:

        private static void locateParent(BeanFactory beanFactory,
        ConditionEvaluationReport report) {
        if (beanFactory != null && report.parent == null
            && beanFactory.containsBean(BEAN_NAME)) {
        report.parent = beanFactory.getBean(BEAN_NAME,
                ConditionEvaluationReport.class);
        }
        }

        这里很明显,由于当前环境下 AnnotationConfigEmbeddedWebApplicationContext 中的BeanFactory 是顶层容器,因此 其 ParentBeanFactory 是不存在的,因此该方法是不会执行的.

    AutoConfigurationReportLoggingInitializer#initialize

    代码如下:

    public void initialize(ConfigurableApplicationContext applicationContext) {
        this.applicationContext = applicationContext;
        applicationContext.addApplicationListener(new AutoConfigurationReportListener());
        if (applicationContext instanceof GenericApplicationContext) {
            // Get the report early in case the context fails to load
            this.report = ConditionEvaluationReport
                    .get(this.applicationContext.getBeanFactory());
        }
    }

    3件事:

    1. 给applicationContext进行赋值
    2. 添加ApplicationListener
    3. 如果当前的applicationContext 是GenericApplicationContext 实例的话,就给report进行赋值.很明显,会执行赋值的.执行如下代码:

      public static ConditionEvaluationReport get(
          ConfigurableListableBeanFactory beanFactory) {
      synchronized (beanFactory) {
          ConditionEvaluationReport report;
          if (beanFactory.containsSingleton(BEAN_NAME)) {
              report = beanFactory.getBean(BEAN_NAME, ConditionEvaluationReport.class);
          }
          else {
              report = new ConditionEvaluationReport();
              beanFactory.registerSingleton(BEAN_NAME, report);
          }
          locateParent(beanFactory.getParentBeanFactory(), report);
          return report;
      }
      }

    2件事:

    1. 如果当前beanFactory包含autoConfigurationReport定义的话,就从beanFactory中获取,否则就实例化一个,然后进行注册
    2. 如果存在父容器的话,就从父容器中获取。

    很明显,这里是不存在父容器的,并且beanFactory是不包含autoConfigurationReport的定义,因此会实例化后再进行注册.

  5. 视线回到SpringApplication#prepareContext中的第5步,打印日志.代码如下:

    if (this.logStartupInfo) {
            logStartupInfo(context.getParent() == null);
            logStartupProfileInfo(context);
        }

    3件事

    1. 判断是否允许打印启动信息,默认是true.如果为false,则不进行打印.
    2. 调用logStartupInfo进行打印.代码如下:

      protected void logStartupInfo(boolean isRoot) {
      if (isRoot) {
          new StartupInfoLogger(this.mainApplicationClass)
                  .logStarting(getApplicationLog());
      }
      }

      由于此时的context为顶级容器,因此为实例化StartupInfoLogger,实例化时将启动类传入构造器,然后调用其logStarting方法.调用时,首先getApplicationLog获得启动类的log.代码如下:

      protected Log getApplicationLog() {
      if (this.mainApplicationClass == null) {
          return logger;
      }
      return LogFactory.getLog(this.mainApplicationClass);
      }

      由于此时的mainApplicationClass不为null,因此会实例化启动类的Log.

      public void logStarting(Log log) {
      Assert.notNull(log, "Log must not be null");
          if (log.isInfoEnabled()) {
              log.info(getStartupMessage());
          }
          if (log.isDebugEnabled()) {
              log.debug(getRunningMessage());
          }
      }

      2件事:

      1. 如果日志级别是info的话,调用getStartupMessage进行打印.代码如下:

        private String getStartupMessage() {
        StringBuilder message = new StringBuilder();
        message.append("Starting ");
        message.append(getApplicationName());
        message.append(getVersion(this.sourceClass));
        message.append(getOn());
        message.append(getPid());
        message.append(getContext());
        return message.toString();
        }

        会打印启动类名,启动类所在的版本号,主机名,进程id,上下文.打印的日志如下;

        2017-12-25 10:25:22.276  INFO 50826 --- [           main] com.example.demo.DemoApplication         : Starting DemoApplication on localhost with PID 50826 (/Users/hejiarui/Documents/spring-boot-source/demo/target/classes started by hejiarui in /Users/hejiarui/Documents/spring-boot-source/demo)
      2. 如果日志级别是debug的话,调用getRunningMessage进行打印.代码如下:

        private StringBuilder getRunningMessage() {
        StringBuilder message = new StringBuilder();
        message.append("Running with Spring Boot");
        message.append(getVersion(getClass()));
        message.append(", Spring");
        message.append(getVersion(ApplicationContext.class));
        return message;
        }

        打印spring boot 的版本号,ApplicationContext的版本号,打印如下:

        2017-12-25 10:29:02.626 DEBUG 50852 --- [           main] com.example.demo.DemoApplication         : Running with Spring Boot, Spring v4.3.13.RELEASE   
  6. 第7步代码如下:

    protected void load(ApplicationContext context, Object[] sources) {
        if (logger.isDebugEnabled()) {
            logger.debug(
                    "Loading source " + StringUtils.arrayToCommaDelimitedString(sources));
        }
        // 1. 实例化BeanDefinitionLoader
        BeanDefinitionLoader loader = createBeanDefinitionLoader(
                getBeanDefinitionRegistry(context), sources);
        // 2. 如果当前的beanNameGenerator 不会null的话,就将SpringApplication中的beanNameGenerator赋值给BeanDefinitionLoader
        if (this.beanNameGenerator != null) {
            loader.setBeanNameGenerator(this.beanNameGenerator);
        }
        // 3. 如果当前的resourceLoader 不会null的话,就将SpringApplication中的resourceLoader赋值给BeanDefinitionLoader
        if (this.resourceLoader != null) {
            loader.setResourceLoader(this.resourceLoader);
        }
        // 4. 如果当前的environment 不会null的话,就将SpringApplication中的environment赋值给BeanDefinitionLoader
        if (this.environment != null) {
            loader.setEnvironment(this.environment);
        }
        // 5. 调用load方法进行加载
        loader.load();
    }

    5件事:

    1. 实例化BeanDefinitionLoader.代码如下:

      protected BeanDefinitionLoader createBeanDefinitionLoader(
          BeanDefinitionRegistry registry, Object[] sources) {
      return new BeanDefinitionLoader(registry, sources);
      }

      构造器如下:

      BeanDefinitionLoader(BeanDefinitionRegistry registry, Object... sources) {
      Assert.notNull(registry, "Registry must not be null");
      Assert.notEmpty(sources, "Sources must not be empty");
      this.sources = sources;
      this.annotatedReader = new AnnotatedBeanDefinitionReader(registry);
      this.xmlReader = new XmlBeanDefinitionReader(registry);
      if (isGroovyPresent()) {
          this.groovyReader = new GroovyBeanDefinitionReader(registry);
      }
      this.scanner = new ClassPathBeanDefinitionScanner(registry);
      this.scanner.addExcludeFilter(new ClassExcludeFilter(sources));
      }

      5件事.

      1. 将sources赋值给BeanDefinitionLoader中的sources
      2. 实例化AnnotatedBeanDefinitionReader.该实例化的过程我们之前有分析过
      3. 实例化了XmlBeanDefinitionReader
      4. 判断是否是在groovy的环境中,如果是的话,就实例化GroovyBeanDefinitionReader.一般情况下,是不会实例化的.判断代码如下:

        private boolean isGroovyPresent() {
        return ClassUtils.isPresent("groovy.lang.MetaClass", null);
        }
      5. 实例化ClassPathBeanDefinitionScanner.该实例化的过程我们之前有分析过.并将启动类,添加到ClassPathBeanDefinitionScanner的ExcludeFilter中。
    2. 如果当前的beanNameGenerator 不会null的话,就将SpringApplication中的beanNameGenerator赋值给BeanDefinitionLoader.对于当前是不会进行赋值的.

    3. 如果当前的resourceLoader 不会null的话,就将SpringApplication中的resourceLoader赋值给BeanDefinitionLoader.对于当前是不会进行赋值的.
    4. 如果当前的environment 不会null的话,就将SpringApplication中的environment赋值给BeanDefinitionLoader.对于当前是不会进行赋值的.
    5. 调用load方法进行加载.代码如下:

      public int load() {
          int count = 0;
          for (Object source : this.sources) {
              count += load(source);
          }
          return count;
      }

      2件事:

      1. 声明一个计数器,该计数器统计的是sources中加载bean的数量.
      2. 遍历sources,进行加载.

        代码如下:

        private int load(Object source) {
        Assert.notNull(source, "Source must not be null");
        if (source instanceof Class) {
            return load((Class) source);
        }
        if (source instanceof Resource) {
            return load((Resource) source);
        }
        if (source instanceof Package) {
            return load((Package) source);
        }
        if (source instanceof CharSequence) {
            return load((CharSequence) source);
        }
        throw new IllegalArgumentException("Invalid source type " + source.getClass());
        }

        判断source 的类型,然后调用相应的load方法进行加载,由于我们此时传入的是启动类,因此会调用如下方法,代码如下:

        private int load(Class source) {
        if (isGroovyPresent()) {
        // Any GroovyLoaders added in beans{} DSL can contribute beans here
        if (GroovyBeanDefinitionSource.class.isAssignableFrom(source)) {
            GroovyBeanDefinitionSource loader = BeanUtils.instantiateClass(source,
                    GroovyBeanDefinitionSource.class);
            load(loader);
        }
        }
        if (isComponent(source)) {
        // 进行注册
        this.annotatedReader.register(source);
        return 1;
        }
        return 0;
        }

        2件事:

        1. 如果是Groovy环境下,并且该类是GroovyBeanDefinitionSource的子类的话,就调用BeanDefinitionLoader#load(GroovyBeanDefinitionSource) 进行加载,很明显,是不会执行的.
        2. 如果当前类是Component注解的话,就调用AnnotatedBeanDefinitionReader#register进行加载.判断的方法如下:

          private boolean isComponent(Class type) {
          // This has to be a bit of a guess. The only way to be sure that this type is
          // eligible is to make a bean definition out of it and try to instantiate it.
          if (AnnotationUtils.findAnnotation(type, Component.class) != null) {
          return true;
          }
          // Nested anonymous classes are not eligible for registration, nor are groovy
          // closures
          if (type.getName().matches(".*\\$_.*closure.*") || type.isAnonymousClass()
              || type.getConstructors() == null || type.getConstructors().length == 0) {
          return false;
          }
          return true;
          }

          3件事

          1. 如果当前类上有@Component 注解的话,则返回true.
          2. 如果当前类的类名匹配.*$_.*closure.* ,或者是一个匿名类,或者构造器不存在的话,返回false.
          3. 如果以上都不匹配的话,返回true.

          由于我们在启动类上加了@SpringBootApplication的注解,又由于@SpringBootApplication中存在@SpringBootConfiguration,而@SpringBootConfiguration中又存在@Configuration,最终在@Configuration中存在@Component,因此匹配1,因此返回true.

        3. 如果以上都没匹配到的话,就返回0.
  7. AnnotatedBeanDefinitionReader#register ,通过遍历annotatedClasses,依次调用registerBean进行加载,代码如下:

    public void register(Class... annotatedClasses) {
        for (Class annotatedClass : annotatedClasses) {
            registerBean(annotatedClass);
        }
    }

    registerBean代码如下:

    public void registerBean(Class annotatedClass) {
        registerBean(annotatedClass, null, (Classextends Annotation>[]) null);
    }

    调用:

    public void registerBean(Class annotatedClass, String name, Classextends Annotation>... qualifiers) {
        AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(annotatedClass);
        if (this.conditionEvaluator.shouldSkip(abd.getMetadata())) {
            return;
        }
    
        ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(abd);
        abd.setScope(scopeMetadata.getScopeName());
        String beanName = (name != null ? name : this.beanNameGenerator.generateBeanName(abd, this.registry));
        AnnotationConfigUtils.processCommonDefinitionAnnotations(abd);
        if (qualifiers != null) {
            for (Classextends Annotation> qualifier : qualifiers) {
                if (Primary.class == qualifier) {
                    abd.setPrimary(true);
                }
                else if (Lazy.class == qualifier) {
                    abd.setLazyInit(true);
                }
                else {
                    abd.addQualifier(new AutowireCandidateQualifier(qualifier));
                }
            }
        }
    
        BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd, beanName);
        definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
        BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);
    }

    9件事:

    1. 实例化AnnotatedGenericBeanDefinition.该类的继承结构如下:

      spring boot 源码解析8-SpringApplication#run第8步_第1张图片
      由继承结构可知.会首先实例化AbstractBeanDefinition,执行如下构造器.代码如下:

      protected AbstractBeanDefinition() {
          this(null, null);
      }

      调用

      protected AbstractBeanDefinition(ConstructorArgumentValues cargs, MutablePropertyValues pvs) {
          setConstructorArgumentValues(cargs);
          setPropertyValues(pvs);
      }

      2件事:

      1. 调用 setConstructorArgumentValues 实例化constructorArgumentValues.代码如下:

        public void setConstructorArgumentValues(ConstructorArgumentValues constructorArgumentValues) {
        this.constructorArgumentValues =
            (constructorArgumentValues != null ? constructorArgumentValues : new ConstructorArgumentValues());
        }

        由于传入的constructorArgumentValues 为null,因此会实例化ConstructorArgumentValues.

      2. 调用setPropertyValues 对propertyValues 进行赋值,代码如下:

        public void setPropertyValues(MutablePropertyValues propertyValues) {
        this.propertyValues = (propertyValues != null ? propertyValues : new MutablePropertyValues());
        }

        由于传入的propertyValues为null,因此会实例化MutablePropertyValues.

      接下来实例化AnnotatedGenericBeanDefinition,构造器如下:

      public AnnotatedGenericBeanDefinition(Class beanClass) {
      setBeanClass(beanClass);
      this.metadata = new StandardAnnotationMetadata(beanClass, true);
      }

      2件事:

      1. 对beanClass属性赋值为传入的beanClass.
      2. 实例化StandardAnnotationMetadata.
    2. 如果应该跳过加载的话,就直接return. 判断逻辑如下:

      public boolean shouldSkip(AnnotatedTypeMetadata metadata, ConfigurationPhase phase) {
      // 如果这个类没有被@Conditional注解所修饰,不会skip
      if (metadata == null || !metadata.isAnnotated(Conditional.class.getName())) {
          return false;
      }
      
      // 如果参数中沒有设置条件注解的生效阶段
      if (phase == null) {
          // 是配置类的话直接使用PARSE_CONFIGURATION阶段
          if (metadata instanceof AnnotationMetadata &&
                  ConfigurationClassUtils.isConfigurationCandidate((AnnotationMetadata) metadata)) {
              return shouldSkip(metadata, ConfigurationPhase.PARSE_CONFIGURATION);
          }
          // 否则使用REGISTER_BEAN阶段
          return shouldSkip(metadata, ConfigurationPhase.REGISTER_BEAN);
      }
      
      List conditions = new ArrayList(); // 要解析的配置类的条件集合
      // 获取配置类的条件注解得到条件数据,并添加到集合中
      for (String[] conditionClasses : getConditionClasses(metadata)) {
          for (String conditionClass : conditionClasses) {
              Condition condition = getCondition(conditionClass, this.context.getClassLoader());
              conditions.add(condition);
          }
      }
      
      AnnotationAwareOrderComparator.sort(conditions);
      
      for (Condition condition : conditions) {
          ConfigurationPhase requiredPhase = null;
          if (condition instanceof ConfigurationCondition) {
              requiredPhase = ((ConfigurationCondition) condition).getConfigurationPhase();
          }
          if (requiredPhase == null || requiredPhase == phase) {
              // 阶段不满足条件的话,返回true并跳过这个bean的解析
              if (!condition.matches(this.context, metadata)) {
                  return true;
              }
          }
      }
      
      return false;
      }

      4件事:

      1. 如果这个类没有被@Conditional注解所修饰,不会skip
      2. 如果参数中沒有设置条件注解的生效阶段

        1. 是配置类的话直接使用PARSE_CONFIGURATION阶段
        2. 否则使用REGISTER_BEAN阶段

        递归调用shouldSkip进行判断.对于当前阶段 ConfigurationPhase为ConfigurationPhase.PARSE_CONFIGURATION.

      3. 获取配置类的条件注解得到条件数据,并添加到集合中.排序
      4. 遍历conditions,进行判断,阶段不满足条件的话,返回true并跳过这个bean的解析
    3. 调用AnnotationScopeMetadataResolver#resolveScopeMetadata解析ScopeMetadata. 代码如下:

      public ScopeMetadata resolveScopeMetadata(BeanDefinition definition) {
      ScopeMetadata metadata = new ScopeMetadata();
      if (definition instanceof AnnotatedBeanDefinition) {
          AnnotatedBeanDefinition annDef = (AnnotatedBeanDefinition) definition;
          AnnotationAttributes attributes = AnnotationConfigUtils.attributesFor(
                  annDef.getMetadata(), this.scopeAnnotationType);
          if (attributes != null) {
              metadata.setScopeName(attributes.getString("value"));
              ScopedProxyMode proxyMode = attributes.getEnum("proxyMode");
              if (proxyMode == null || proxyMode == ScopedProxyMode.DEFAULT) {
                  proxyMode = this.defaultProxyMode;
              }
              metadata.setScopedProxyMode(proxyMode);
          }
      }
      return metadata;
      }

      2件事:

      1. 实例化ScopeMetadata.其默认scopeName为singleton,scopedProxyMode为NO.
      2. 如果BeanDefinition是AnnotatedBeanDefinition实例的话,调用AnnotationConfigUtils#attributesFor获得AnnotationAttributes.如果AnnotationAttributes不会null的话,就为metadata设置ScopeName,设置ScopedProxyMode.此处返回的null.
      3. 如果不是的话,就返回ScopeMetadata.

      因此设置AnnotatedGenericBeanDefinition的scope为singleton

    4. 调用AnnotationBeanNameGenerator#generateBeanName生成beanName,代码如下:

      public String generateBeanName(BeanDefinition definition, BeanDefinitionRegistry registry) {
      // 1. 如果当前类是AnnotatedBeanDefinition,就调用determineBeanNameFromAnnotation生成beanName
      // 如果生成的beanName不为空的话,直接return。否则进入第2步.
      if (definition instanceof AnnotatedBeanDefinition) {
          String beanName = determineBeanNameFromAnnotation((AnnotatedBeanDefinition) definition);
          if (StringUtils.hasText(beanName)) {
              // Explicit bean name found.
              return beanName;
          }
      }
      // 2. Fallback: generate a unique default bean name.
      return buildDefaultBeanName(definition, registry);
      }

      2件事:

      1. 如果当前类是AnnotatedBeanDefinition,就调用determineBeanNameFromAnnotation生成beanName,如果生成的beanName不为空的话,直接return。否则进入第2步.在当前场景,是会进入第2步的.
      2. 经过层层调用最终会调用AnnotationBeanNameGenerator#buildDefaultBeanName获得name,代码如下:


        protected String buildDefaultBeanName(BeanDefinition definition) {
        String shortClassName = ClassUtils.getShortName(definition.getBeanClassName());
        return Introspector.decapitalize(shortClassName);
        }

    5. 调用AnnotationConfigUtils#processCommonDefinitionAnnotations进行处理.代码如下:

      static void processCommonDefinitionAnnotations(AnnotatedBeanDefinition abd, AnnotatedTypeMetadata metadata) {
      if (metadata.isAnnotated(Lazy.class.getName())) {
      abd.setLazyInit(attributesFor(metadata, Lazy.class).getBoolean("value"));
      }
      else if (abd.getMetadata() != metadata && abd.getMetadata().isAnnotated(Lazy.class.getName())) {
      abd.setLazyInit(attributesFor(abd.getMetadata(), Lazy.class).getBoolean("value"));
      }
      if (metadata.isAnnotated(Primary.class.getName())) {
      abd.setPrimary(true);
      }
      if (metadata.isAnnotated(DependsOn.class.getName())) {
      abd.setDependsOn(attributesFor(metadata, DependsOn.class).getStringArray("value"));
      }
      if (abd instanceof AbstractBeanDefinition) {
      AbstractBeanDefinition absBd = (AbstractBeanDefinition) abd;
      if (metadata.isAnnotated(Role.class.getName())) {
          absBd.setRole(attributesFor(metadata, Role.class).getNumber("value").intValue());
      }
      if (metadata.isAnnotated(Description.class.getName())) {
          absBd.setDescription(attributesFor(metadata, Description.class).getString("value"));
      }
      }
      }

      4件事:

      1. 如果有Lazy的注解的话,则设置LazyInit的值
      2. 如果有Primary的注解的话,则设置Primary为true
      3. 如果有DependsOn的注解的话,则设置DependsOn的值
      4. 如果abd 是AbstractBeanDefinition 子类的话

        1. 如果有Role的注解的话,则设置Role的值
        2. 如果有Description的注解的话,则设置Description的值
    6. 设置qualifier,依次遍历传入的qualifiers进行如下判断.

      1. 如果 qualifier 为Primary 的话,设置AnnotatedGenericBeanDefinition#Primary为true.
      2. 如果 qualifier 为 Lazy 的话,就设置AnnotatedGenericBeanDefinition #LazyInit 为true。
      3. 否则 就添加一个AutowireCandidateQualifier的实例到AnnotatedGenericBeanDefinition#qualifiers中.

      由于此时传入qualifier 为null,因此是不会进行遍历的.

    7. 调用applyScopedProxyMode,这是有关代理方面的.代码如下:

      static BeanDefinitionHolder applyScopedProxyMode(
          ScopeMetadata metadata, BeanDefinitionHolder definition, BeanDefinitionRegistry registry) {
      
      ScopedProxyMode scopedProxyMode = metadata.getScopedProxyMode();
      if (scopedProxyMode.equals(ScopedProxyMode.NO)) {
          return definition;
      }
      boolean proxyTargetClass = scopedProxyMode.equals(ScopedProxyMode.TARGET_CLASS);
      return ScopedProxyCreator.createScopedProxy(definition, registry, proxyTargetClass);
      }

      2件事

      1. 如果scopedProxyMode为NO,就直接return。
      2. 否则调用ScopedProxyCreator#createScopedProxy生成BeanDefinitionHolder.

      由于这里的scopedProxyMode为NO,因此是直接进行return的.

  8. 视线回到SpringApplication#prepareContext.接下来该执行最后一步了, 调用listeners的contextLoaded方法.代码如下;

    public void contextLoaded(ConfigurableApplicationContext context) {
        for (SpringApplicationRunListener listener : this.listeners) {
            listener.contextLoaded(context);
        }
    }

    调用EventPublishingRunListener#contextLoaded,代码如下:

    public void contextLoaded(ConfigurableApplicationContext context) {
        for (ApplicationListener listener : this.application.getListeners()) {
            if (listener instanceof ApplicationContextAware) {
                ((ApplicationContextAware) listener).setApplicationContext(context);
            }
            context.addApplicationListener(listener);
        }
        this.initialMulticaster.multicastEvent(
                new ApplicationPreparedEvent(this.application, this.args, context));
    }
    

    2件事

    1. 遍历application 中的ApplicationListener,如果listener 实现了ApplicationContextAware的话,就调用其setApplicationContext进行赋值.当前的如下:

      org.springframework.boot.context.config.ConfigFileApplicationListener,
      org.springframework.boot.context.config.AnsiOutputApplicationListener, 
      org.springframework.boot.logging.LoggingApplicationListener, 
      org.springframework.boot.logging.ClasspathLoggingApplicationListener, 
      org.springframework.boot.autoconfigure.BackgroundPreinitializer, 
      org.springframework.boot.context.config.DelegatingApplicationListener, 
      org.springframework.boot.builder.ParentContextCloserApplicationListener,  
      org.springframework.boot.ClearCachesApplicationListener, 
      org.springframework.boot.context.FileEncodingApplicationListener,
      org.springframework.boot.liquibase.LiquibaseServiceLocatorApplicationListener

      只有ParentContextCloserApplicationListener实现了ApplicationContextAware接口.

    2. 发送ApplicationPreparedEvent 事件.由前可知,会依次调用listener的onApplicationEvent事件,接下来我们就来看看其各自的实现.

    ConfigFileApplicationListener#onApplicationEvent

    代码如下:

    public void onApplicationEvent(ApplicationEvent event) {
        if (event instanceof ApplicationEnvironmentPreparedEvent) {
            onApplicationEnvironmentPreparedEvent(
                    (ApplicationEnvironmentPreparedEvent) event);
        }
        if (event instanceof ApplicationPreparedEvent) {
            onApplicationPreparedEvent(event);
        }
    }

    调用onApplicationPreparedEvent,代码如下:

        private void onApplicationPreparedEvent(ApplicationEvent event) {
        this.logger.replayTo(ConfigFileApplicationListener.class);
        addPostProcessors(((ApplicationPreparedEvent) event).getApplicationContext());
    }

    调用

        protected void addPostProcessors(ConfigurableApplicationContext context) {
        context.addBeanFactoryPostProcessor(
                new PropertySourceOrderingPostProcessor(context));
    }

    最终添加了一个PropertySourceOrderingPostProcessor.

    LoggingApplicationListener#onApplicationEvent

    最终会执行LoggingApplicationListener#onApplicationPreparedEvent,向beanFactory注册了一个id为springBootLoggingSystem,class 为 LoggingSystem 的bean.

    BackgroundPreinitializer#onApplicationEvent

    没有做任何事

    DelegatingApplicationListener#onApplicationEvent

    没有做任何事

  9. 你可能感兴趣的:(spring,boot,spring,boot,源码解析,spring,源码)