目录
1.环境和依赖
1.1.spring boot版本
springboot 2.2.X版本采用的maven构建,2.3.X采用gradle构建,因此采用2.2.X,mavan构建的便于源码阅读。本文以2.2.9为例进行Spring Boot自动装配原理的解析。
1.2.依赖管理
引入Spring Boot的方式有两种
- 引入spring-boot-dependencies的pom文件
- 将spring-boot-starter-parent作为父级pom
这两种方式的底层都是都是一样的,都是引入了spring-boot-dependencies这个pom文件来管理Spring Boot的所有依赖。
SpringBoot中将一类场景要用到的依赖封装成一个starter,spring-boot-dependencies中包含了J2EE中所有场景(starter)的依赖,并声明了依赖的版本号。
2.自动装配
2.1.流程概述
首先所有JAVA程序的入口都是main方法,Spring Boot也不例外,只有main方法执行时,所有流程步骤才会执行,此处我们只是从启动流程中剥离出和自动装配相关的流程来进行单独解析。只需要大致知道自动装配流程有几步即可,如果有其它疑惑看后文的启动过程解析,就能豁然开朗。
自动装配的整个流程可以分为三大步
- 获取过滤列表
- 获取自动配置类列表
- 比对移除、封装返回
1.获取条件列表
获取类自动装载的条件列表。
2.获取自动配置列表
获取自动装载类的列表。
3.比对移除、封装返回
按照条件列表,将不满足被自动装载条件的类移除掉,返回满足条件的类列表。
2.2.三大步前的准备工作
2.2.1.注解入口
@SpringBootApplication
该注解是个复合注解:
  
   - 
    
     
    
    
     
      @Target(ElementType.TYPE)
     
    
- 
    
     
    
    
     
      @Retention(RetentionPolicy.RUNTIME)
     
    
- 
    
     
    
    
     
      @Documented
     
    
- 
    
     
    
    
     
      @Inherited
     
    
- 
    
     
    
    
     
      @SpringBootConfiguration
     
    
- 
    
     
    
    
     
      @EnableAutoConfiguration
     
    
- 
    
     
    
    
     
      @ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
     
    
- 
    
     
    
    
     
       @Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
     
    
- 
    
     
    
    
     
      public 
      @interface SpringBootApplication {
     
    
@EnableAutoConfiguration启动自动装配:
@Import(AutoConfigurationImportSelector.class) ,AutoConfigurationImportSelector会完成所有配置类的获取以及相关的准备工作。
  
   - 
    
     
    
    
     
      @Target(ElementType.TYPE)
     
    
- 
    
     
    
    
     
      @Retention(RetentionPolicy.RUNTIME)
     
    
- 
    
     
    
    
     
      @Documented
     
    
- 
    
     
    
    
     
      @Inherited
     
    
- 
    
     
    
    
     
      @AutoConfigurationPackage
     
    
- 
    
     
    
    
     
      @Import(AutoConfigurationImportSelector.class)
     
    
- 
    
     
    
    
     
      public 
      @interface EnableAutoConfiguration {}
     
    
2.2.2.获取所有配置类
AutoConfigurationImportSelector被加载后,经过层层调用,最终会调用到DeferredImportSelector中:
会去扫描所有@Configuration封装成一个列表返回。
  
   - 
    
     
    
    
     
      public Iterable<Entry> 
      getImports
      () {
     
    
- 
    
     
    
    
                 
      Iterator 
      var1 
      = 
      this.deferredImports.iterator();
     
    
- 
    
     
    
    
      
     
    
- 
    
     
    
    
                 
      while(var1.hasNext()) {
     
    
- 
    
     
    
    
     
                      ConfigurationClassParser.
      DeferredImportSelectorHolder 
      deferredImport 
      = (ConfigurationClassParser.DeferredImportSelectorHolder)var1.next();
     
    
- 
    
     
    
    
                     
      this.group.process(deferredImport.getConfigurationClass().getMetadata(), deferredImport.getImportSelector());
     
    
- 
    
     
    
    
     
                  }
     
    
- 
    
     
    
    
     			
      //将得到的自动配置类按照@order进行排序
     
    
- 
    
     
    
    
                 
      return 
      this.group.selectImports();
     
    
- 
    
     
    
    
     
              }
     
    
2.3.获取过滤列表
2.3.1.目的
获取过滤列表,即去获取META-INF/spring-autoconfigure-metadata.properties这一文件。这个文件中会详细记录Spring Boot自带的各大J2EE场景的自动配置类(@Configuration)各自被自动装载生效的前提条件是什么。
2.3.2.过程
DeferredImportSelector.Group.process()中会首先获取自动装配的过滤条件列表,该列表中记录了待装配的类的装配条件。获取的核心方法是getAutoConfigurationMetadata(),该方法会根据传过来的ClassLoader去遍历加载classpath下的所有依赖,获取依赖中的META-INF/spring-autoconfigure-metadata.properties文件。
  
   - 
    
     
    
    
     
      public 
      void 
      process
      (AnnotationMetadata annotationMetadata, DeferredImportSelector deferredImportSelector) {
     
    
- 
    
     
    
    
     
      			Assert.state(deferredImportSelector 
      instanceof AutoConfigurationImportSelector,
     
    
- 
    
     
    
    
     
      					() -> String.format(
      "Only %s implementations are supported, got %s",
     
    
- 
    
     
    
    
     
      							AutoConfigurationImportSelector.class.getSimpleName(),
     
    
- 
    
     
    
    
     
      							deferredImportSelector.getClass().getName()));
     
    
- 
    
     
    
    
     			
      //获取自动配置类
     
    
- 
    
     
    
    
     			
      AutoConfigurationEntry 
      autoConfigurationEntry 
      = ((AutoConfigurationImportSelector) deferredImportSelector)
     
    
- 
    
     
    
    
     
      					.getAutoConfigurationEntry(getAutoConfigurationMetadata(), annotationMetadata);
     
    
- 
    
     
    
    
     			
      this.autoConfigurationEntries.add(autoConfigurationEntry);
     
    
- 
    
     
    
    
         		
      //解析存放自动配置类
     
    
- 
    
     
    
    
     			
      for (String importClassName : autoConfigurationEntry.getConfigurations()) {
     
    
- 
    
     
    
    
     				
      this.entries.putIfAbsent(importClassName, annotationMetadata);
     
    
- 
    
     
    
    
     
      			}
     
    
- 
    
     
    
    
     
      		}
     
    
- 
    
     
    
    
      
     
    
- 
    
     
    
    
     
      private AutoConfigurationMetadata 
      getAutoConfigurationMetadata
      () {
     
    
- 
    
     
    
    
     			
      if (
      this.autoConfigurationMetadata == 
      null) {
     
    
- 
    
     
    
    
     				
      this.autoConfigurationMetadata = AutoConfigurationMetadataLoader.loadMetadata(
      this.beanClassLoader);
     
    
- 
    
     
    
    
     
      			}
     
    
- 
    
     
    
    
     			
      return 
      this.autoConfigurationMetadata;
     
    
- 
    
     
    
    
     
      		}
     
    
 
  
   - 
    
     
    
    
     
      final 
      class 
      AutoConfigurationMetadataLoader {
     
    
- 
    
     
    
    
      
     
    
- 
    
     
    
    
     	
      protected 
      static 
      final 
      String 
      PATH 
      = 
      "META-INF/spring-autoconfigure-metadata.properties";
     
    
- 
    
     
    
    
      
     
    
- 
    
     
    
    
     	
      private 
      AutoConfigurationMetadataLoader
      () {
     
    
- 
    
     
    
    
     
      	}
     
    
- 
    
     
    
    
      
     
    
- 
    
     
    
    
     	
      static AutoConfigurationMetadata 
      loadMetadata
      (ClassLoader classLoader) {
     
    
- 
    
     
    
    
     		
      return loadMetadata(classLoader, PATH);
     
    
- 
    
     
    
    
     
      	}
     
    
- 
    
     
    
    
      
     
    
- 
    
     
    
    
     	
      static AutoConfigurationMetadata 
      loadMetadata
      (ClassLoader classLoader, String path) {
     
    
- 
    
     
    
    
     		
      try {
     
    
- 
    
     
    
    
     
      			Enumeration<URL> urls = (classLoader != 
      null) ? classLoader.getResources(path)
     
    
- 
    
     
    
    
     
      					: ClassLoader.getSystemResources(path);
     
    
- 
    
     
    
    
     			
      Properties 
      properties 
      = 
      new 
      Properties();
     
    
- 
    
     
    
    
     			
      while (urls.hasMoreElements()) {
     
    
- 
    
     
    
    
     
      				properties.putAll(PropertiesLoaderUtils.loadProperties(
      new 
      UrlResource(urls.nextElement())));
     
    
- 
    
     
    
    
     
      			}
     
    
- 
    
     
    
    
     			
      return loadMetadata(properties);
     
    
- 
    
     
    
    
     
      		}
     
    
- 
    
     
    
    
     		
      catch (IOException ex) {
     
    
- 
    
     
    
    
     			
      throw 
      new 
      IllegalArgumentException(
      "Unable to load @ConditionalOnClass location [" + path + 
      "]", ex);
     
    
- 
    
     
    
    
     
      		}
     
    
- 
    
     
    
    
     
      	}
     
    
 过滤列表中会以KV键值对的方式记录装配条件,例如:
org.springframework.boot.autoconfigure.amqp.RabbitAnnotationDrivenConfiguration.ConditionalOnClass=org.springframework.amqp.rabbit.annotation.EnableRabbit
2.4.装载
2.4.1.目的
-  获取自动配置列表 
-  对比过滤列表,移除不满足自动装载的类 
-  封装返回 
2.4.2.过程
process()方法中会调用getAutoConfigurationEntry()方法,并将过滤列表传和ClassLoader传过去,在getCandidateConfigurations()方法中通过传递的ClassLoader获取自动装配的列表"META-INF/spring.factories",然后比对过滤列表,将满足条件的待装配类的全路径记录在AutoConfigurationImportSelector.AutoConfigurationGroup的一个叫autoConfigurationEntries的List中。
  
   - 
    
     
    
    
     
      protected AutoConfigurationEntry 
      getAutoConfigurationEntry
      (AutoConfigurationMetadata autoConfigurationMetadata,
     
    
- 
    
     
    
    
     
       AnnotationMetadata annotationMetadata) {
     
    
- 
    
     
    
    
        
      if (!isEnabled(annotationMetadata)) {
     
    
- 
    
     
    
    
           
      return EMPTY_ENTRY;
     
    
- 
    
     
    
    
     
         }
     
    
- 
    
     
    
    
        
      AnnotationAttributes 
      attributes 
      = getAttributes(annotationMetadata);
     
    
- 
    
     
    
    
        
      //从spring.factories中加载所有自动配置类
     
    
- 
    
     
    
    
     
         List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
     
    
- 
    
     
    
    
        
      //移除重复配置类
     
    
- 
    
     
    
    
     
         configurations = removeDuplicates(configurations);
     
    
- 
    
     
    
    
        
      //得到指定要移除的类(@SpringBootApplication(exclude=FreeMarkerAutoConfiguration.class))
     
    
- 
    
     
    
    
     
         Set<String> exclusions = getExclusions(annotationMetadata, attributes);
     
    
- 
    
     
    
    
        
      //检查指定要移除的类,如果不是配置类,抛出异常
     
    
- 
    
     
    
    
     
         checkExcludedClasses(configurations, exclusions);
     
    
- 
    
     
    
    
        
      //移除指定要移除的自动配置类
     
    
- 
    
     
    
    
     
         configurations.removeAll(exclusions);
     
    
- 
    
     
    
    
        
      //获取满足条件的自动配置类列表
     
    
- 
    
     
    
    
     
         configurations = filter(configurations, autoConfigurationMetadata);
     
    
- 
    
     
    
    
        
      //记录下符合条件的对象,并封装在实体中返回
     
    
- 
    
     
    
    
     
         fireAutoConfigurationImportEvents(configurations, exclusions);
     
    
- 
    
     
    
    
        
      return 
      new 
      AutoConfigurationEntry(configurations, exclusions);
     
    
- 
    
     
    
    
     
      }
     
    
 一切执行完毕后会回到入口出继续向下执行this.group.selectImports(),最终会调用到AutoConfigurationImportSelector的selectImports()方法,在该方法中会根据@order对自动配置类进行排序。
  
   - 
    
     
    
    
     
      public Iterable<Entry> 
      selectImports
      () {
     
    
- 
    
     
    
    
        
      if (
      this.autoConfigurationEntries.isEmpty()) {
     
    
- 
    
     
    
    
           
      return Collections.emptyList();
     
    
- 
    
     
    
    
     
         }
     
    
- 
    
     
    
    
     
         Set<String> allExclusions = 
      this.autoConfigurationEntries.stream()
     
    
- 
    
     
    
    
     
               .map(AutoConfigurationEntry::getExclusions).flatMap(Collection::stream).collect(Collectors.toSet());
     
    
- 
    
     
    
    
     
         Set<String> processedConfigurations = 
      this.autoConfigurationEntries.stream()
     
    
- 
    
     
    
    
     
               .map(AutoConfigurationEntry::getConfigurations).flatMap(Collection::stream)
     
    
- 
    
     
    
    
     
               .collect(Collectors.toCollection(LinkedHashSet::
      new));
     
    
- 
    
     
    
    
     
         processedConfigurations.removeAll(allExclusions);
     
    
- 
    
     
    
    
      
     
    
- 
    
     
    
    
        
      return sortAutoConfigurations(processedConfigurations, getAutoConfigurationMetadata()).stream()
     
    
- 
    
     
    
    
     
               .map((importClassName) -> 
      new 
      Entry(
      this.entries.get(importClassName), importClassName))
     
    
- 
    
     
    
    
     
               .collect(Collectors.toList());
     
    
- 
    
     
    
    
     
      }
     
    
 2.5.自动配置
在自动装载步骤中已经获得需要加载的自动配置类的全路径,接下来就是自动配置。
以随便一个AutoConfiguration类为例:
头上的一大串@Conditional注解其实就是过滤时的过滤条件,过滤列表其实就是通过这些条件注解生成的。
  
   - 
    
     
    
    
     
      @Configuration(proxyBeanMethods = false)
     
    
- 
    
     
    
    
     
      @EnableConfigurationProperties(HttpProperties.class)
     
    
- 
    
     
    
    
     
      @ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)
     
    
- 
    
     
    
    
     
      @ConditionalOnClass(CharacterEncodingFilter.class)
     
    
- 
    
     
    
    
     
      @ConditionalOnProperty(prefix = "spring.http.encoding", value = "enabled", matchIfMissing = true)
     
    
- 
    
     
    
    
     
      public 
      class 
      HttpEncodingAutoConfiguration {}
     
    
这个@Configuration满足条件后其中的@Bean都会被自动装入IOC。
3.启动过程
3.1.整体流程
Spring boot的启动过程就是围绕上下文的创建、准备、刷新(填充)展开的。
spring应用上下文和servletContext不是一个东西,servlet上下文用来维系当前应用的一块共享空间,目的是实现资源和数据在应用中的全局共享。spring的上下文是一个维护Bean定义以及对象之间协作关系的高级接口,目的是维护好整个spring中的资源,如配置文件、Bean对象等,其涵盖了IOC,但不只有IOC,可以理解为Spring应用的一个抽象。
在SpringApplication的run()方法中创建应用上下文,整个SpringApplication的run方法主要完成四个核心动作:
-  prepareEnvironment 创建环境信息对象,解析环境参数,包含配置文件、命令行传参等。 
-  createApplicationContext 创建应用上下文对象 
-  prepareContext 准备应用上下文对象 
-  refreshContext 刷新应用上下文对象 
  
   - 
    
     
    
    
     
      // 类 SpringApplication 代码片段
     
    
- 
    
     
    
    
     	
      public ConfigurableApplicationContext 
      run
      (String... args) {
     
    
- 
    
     
    
    
     		
      StopWatch 
      stopWatch 
      = 
      new 
      StopWatch();
     
    
- 
    
     
    
    
     
      		stopWatch.start();
     
    
- 
    
     
    
    
     		
      ConfigurableApplicationContext 
      context 
      = 
      null;
     
    
- 
    
     
    
    
     
      		Collection<SpringBootExceptionReporter> exceptionReporters = 
      new 
      ArrayList<>();
     
    
- 
    
     
    
    
     
      		configureHeadlessProperty();
     
    
- 
    
     
    
    
     		
      SpringApplicationRunListeners 
      listeners 
      = getRunListeners(args);
     
    
- 
    
     
    
    
     
      		listeners.starting();
     
    
- 
    
     
    
    
     		
      try {
     
    
- 
    
     
    
    
               
      // 包装通过命令行传入的名命令行参数
     
    
- 
    
     
    
    
     			
      ApplicationArguments 
      applicationArguments 
      = 
      new 
      DefaultApplicationArguments(args);
     
    
- 
    
     
    
    
               
      // 结合命令行参数 准备环境对象,该环境对象将会被设置到应用上下文对象 ApplicationContext 上 ,
     
    
- 
    
     
    
    
               
      // 环境对象通常包含如下信息 : 
     
    
- 
    
     
    
    
               
      // 1. profile
     
    
- 
    
     
    
    
               
      // 2. system properties
     
    
- 
    
     
    
    
               
      // 3. system environment
     
    
- 
    
     
    
    
               
      // 4. commandline arguments
     
    
- 
    
     
    
    
               
      // 5. spring 配置文件
     
    
- 
    
     
    
    
               
      // 6. 一个随机值属性源 random
     
    
- 
    
     
    
    
               
      // 对于当前 WebFlux 应用来讲,这里实现类会使用 StandardReactiveWebEnvironment
     
    
- 
    
     
    
    
     			
      ConfigurableEnvironment 
      environment 
      = prepareEnvironment(listeners, applicationArguments);
     
    
- 
    
     
    
    
     
      			configureIgnoreBeanInfo(environment);
     
    
- 
    
     
    
    
     			
      Banner 
      printedBanner 
      = printBanner(environment);
     
    
- 
    
     
    
    
               
      // 创建应用上下文对象 ApplicationContext 
     
    
- 
    
     
    
    
               
      // 实现类会采用 : AnnotationConfigReactiveWebServerApplicationContext
     
    
- 
    
     
    
    
     
      			context = createApplicationContext();
     
    
- 
    
     
    
    
     
      			exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,
     
    
- 
    
     
    
    
     					
      new 
      Class[] { ConfigurableApplicationContext.class }, context);
     
    
- 
    
     
    
    
               
      // 准备应用上下文对象 ApplicationContext 
     
    
- 
    
     
    
    
               
      // 1. 关联环境信息对象到应用上下文对象
     
    
- 
    
     
    
    
               
      // 2. 对象创建后置处理 : 设置容器的类型转换服务
     
    
- 
    
     
    
    
               
      // 3. 初始化应用上下文对象:调用各个 ApplicationContextInitializer
     
    
- 
    
     
    
    
               
      // 4. 广播事件 : ApplicationContextInitializedEvent
     
    
- 
    
     
    
    
               
      // 5. 将应用程序参数作为一个 bean 注册到容器 : springApplicationArguments
     
    
- 
    
     
    
    
               
      // 6. 将应用程序入口类作为 bean 注册到容器 (load)
     
    
- 
    
     
    
    
               
      // 7. 上下文加载完成生命周期事件回调,为各个实现了 接口 ApplicationContextAware 的 
     
    
- 
    
     
    
    
               
      // ApplicationListener 设置应用上下文对象属性, 并广播事件 : ApplicationPreparedEvent
     
    
- 
    
     
    
    
     
      			prepareContext(context, environment, listeners, applicationArguments, printedBanner);
     
    
- 
    
     
    
    
               
      // 刷新应用上下文对象 ApplicationContext 
     
    
- 
    
     
    
    
               
      // 主要是调用应用上下文对象 ApplicationContext 自身的 refresh 方法
     
    
- 
    
     
    
    
     
      			refreshContext(context);
     
    
- 
    
     
    
    
     
      			afterRefresh(context, applicationArguments);
     
    
- 
    
     
    
    
     
      			stopWatch.stop();
     
    
- 
    
     
    
    
     			
      if (
      this.logStartupInfo) {
     
    
- 
    
     
    
    
     				
      new 
      StartupInfoLogger(
      this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);
     
    
- 
    
     
    
    
     
      			}
     
    
- 
    
     
    
    
     
      			listeners.started(context);
     
    
- 
    
     
    
    
                 
     
    
- 
    
     
    
    
               
      // 应用程序上下文对象 ApplicationContext 已经准备就绪,
     
    
- 
    
     
    
    
               
      // 现在调用各种开发人员或者框架其他部分定义的 
     
    
- 
    
     
    
    
               
      // ApplicationRunner 或者 CommandLineRunner
     
    
- 
    
     
    
    
     
      			callRunners(context, applicationArguments);
     
    
- 
    
     
    
    
     
      		}
     
    
- 
    
     
    
    
     		
      catch (Throwable ex) {
     
    
- 
    
     
    
    
     
      			handleRunFailure(context, ex, exceptionReporters, listeners);
     
    
- 
    
     
    
    
     			
      throw 
      new 
      IllegalStateException(ex);
     
    
- 
    
     
    
    
     
      		}
     
    
- 
    
     
    
    
      
     
    
- 
    
     
    
    
     		
      try {
     
    
- 
    
     
    
    
     
      			listeners.running(context);
     
    
- 
    
     
    
    
     
      		}
     
    
- 
    
     
    
    
     		
      catch (Throwable ex) {
     
    
- 
    
     
    
    
     
      			handleRunFailure(context, ex, exceptionReporters, 
      null);
     
    
- 
    
     
    
    
     			
      throw 
      new 
      IllegalStateException(ex);
     
    
- 
    
     
    
    
     
      		}
     
    
- 
    
     
    
    
     		
      return context;
     
    
- 
    
     
    
    
     
      	}
     
    
 3.2.创建环境信息对象
  
   - 
    
     
    
    
     
      // SpringApplication 代码片段
     
    
- 
    
     
    
    
     	
      private ConfigurableEnvironment 
      prepareEnvironment
      (SpringApplicationRunListeners listeners,
     
    
- 
    
     
    
    
     
       ApplicationArguments applicationArguments) {
     
    
- 
    
     
    
    
     		
      // Create and configure the environment
     
    
- 
    
     
    
    
            
      // 创建环境信息对象 environment
     
    
- 
    
     
    
    
     		
      ConfigurableEnvironment 
      environment 
      = getOrCreateEnvironment();
     
    
- 
    
     
    
    
            
      // 将应用程序参数关联到环境信息对象 environment
     
    
- 
    
     
    
    
     
      		configureEnvironment(environment, applicationArguments.getSourceArgs());
     
    
- 
    
     
    
    
            
      // 发布应用程序事件 : 环境信息对象准备好了 ,
     
    
- 
    
     
    
    
            
      // 同步调用各个事件监听器
     
    
- 
    
     
    
    
     
      		listeners.environmentPrepared(environment);
     
    
- 
    
     
    
    
     
      		bindToSpringApplication(environment);
     
    
- 
    
     
    
    
     		
      if (!
      this.isCustomEnvironment) {
     
    
- 
    
     
    
    
     
      			environment = 
      new 
      EnvironmentConverter(getClassLoader()).convertEnvironmentIfNecessary(environment,
     
    
- 
    
     
    
    
     
      					deduceEnvironmentClass());
     
    
- 
    
     
    
    
     
      		}       
     
    
- 
    
     
    
    
     
      		ConfigurationPropertySources.attach(environment);
     
    
- 
    
     
    
    
     		
      return environment;
     
    
- 
    
     
    
    
     
      	}
     
    
 普通web应用和reactive创建的环境信息对象类型不同,但是实际功能相同,并没有什么太大区别。
  
   - 
    
     
    
    
     
      // SpringApplication 代码片段
     
    
- 
    
     
    
    
         
      private ConfigurableEnvironment 
      getOrCreateEnvironment
      () {
     
    
- 
    
     
    
    
     		
      if (
      this.environment != 
      null) {
     
    
- 
    
     
    
    
     			
      return 
      this.environment;
     
    
- 
    
     
    
    
     
      		}
     
    
- 
    
     
    
    
     		
      switch (
      this.webApplicationType) {
     
    
- 
    
     
    
    
     		
      case SERVLET:
     
    
- 
    
     
    
    
     			
      return 
      new 
      StandardServletEnvironment();
     
    
- 
    
     
    
    
     		
      case REACTIVE:
     
    
- 
    
     
    
    
     			
      return 
      new 
      StandardReactiveWebEnvironment();
     
    
- 
    
     
    
    
     		
      default:
     
    
- 
    
     
    
    
     			
      return 
      new 
      StandardEnvironment();
     
    
- 
    
     
    
    
     
      		}
     
    
- 
    
     
    
    
     
      	}
     
    
3.3.创建应用上下文对象
根据之前环境推断中得到的当前应用的环境类型来创建不同类型的应用上下文。
  
   - 
    
     
    
    
     
      // SpringApplication 代码片段
     
    
- 
    
     
    
    
     	
      protected ConfigurableApplicationContext 
      createApplicationContext
      () {
     
    
- 
    
     
    
    
     
      		Class<?> contextClass = 
      this.applicationContextClass;
     
    
- 
    
     
    
    
     		
      if (contextClass == 
      null) {
     
    
- 
    
     
    
    
     			
      try {
     
    
- 
    
     
    
    
                  
      // 根据 this.webApplicationType 确定应用上下文实现类
     
    
- 
    
     
    
    
     				
      switch (
      this.webApplicationType) {
     
    
- 
    
     
    
    
     				
      case SERVLET:
     
    
- 
    
     
    
    
                 
      // DEFAULT_SERVLET_WEB_CONTEXT_CLASS 常量值为 : 
     
    
- 
    
     
    
    
                 
      // org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext
     
    
- 
    
     
    
    
                 
      // 对应 Spring MVC Servlet Web 环境
     
    
- 
    
     
    
    
     
      					contextClass = Class.forName(DEFAULT_SERVLET_WEB_CONTEXT_CLASS);
     
    
- 
    
     
    
    
     					
      break;
     
    
- 
    
     
    
    
     				
      case REACTIVE:
     
    
- 
    
     
    
    
                 
      // DEFAULT_REACTIVE_WEB_CONTEXT_CLASS 常量值为 : 
     
    
- 
    
     
    
    
                 
      // org.springframework.boot.web.reactive.context.AnnotationConfigReactiveWebServerApplicationContext
     
    
- 
    
     
    
    
                 
      // 对应 Spring WebFlux Reactive Web 环境
     
    
- 
    
     
    
    
     
      					contextClass = Class.forName(DEFAULT_REACTIVE_WEB_CONTEXT_CLASS);
     
    
- 
    
     
    
    
     					
      break;
     
    
- 
    
     
    
    
     				
      default:
     
    
- 
    
     
    
    
                 
      // DEFAULT_CONTEXT_CLASS 常量值为 : 
     
    
- 
    
     
    
    
                 
      // org.springframework.context.annotation.AnnotationConfigApplicationContext
     
    
- 
    
     
    
    
                 
      // 不对应任何 Web 环境
     
    
- 
    
     
    
    
     
      					contextClass = Class.forName(DEFAULT_CONTEXT_CLASS);
     
    
- 
    
     
    
    
     
      				}
     
    
- 
    
     
    
    
     
      			}
     
    
- 
    
     
    
    
     			
      catch (ClassNotFoundException ex) {
     
    
- 
    
     
    
    
     				
      throw 
      new 
      IllegalStateException(
     
    
- 
    
     
    
    
     			
      "Unable create a default ApplicationContext, " + 
      "please specify an ApplicationContextClass",
     
    
- 
    
     
    
    
     
      			ex);
     
    
- 
    
     
    
    
     
      			}
     
    
- 
    
     
    
    
     
      		}
     
    
- 
    
     
    
    
             
     
    
- 
    
     
    
    
            
      // 确定应用上下文实现类之后,实例化应用上下文对象 
     
    
- 
    
     
    
    
     		
      return (ConfigurableApplicationContext) BeanUtils.instantiateClass(contextClass);
     
    
- 
    
     
    
    
     
      	}
     
    
 3.4.刷新应用上下文对象
3.4.1.准备刷新
这一步主要是完成刷新前的准备工作,将除IOC相关的一切context中的东西全部赋值初始化好。
主要完成以下动作:
-  关联环境信息 
-  查找调用各种前置、后置处理器(自定义的、自带的) 
-  调用各种回调 
-  获取主启动类的路径,将主启动类封装成一个BeanDefinition 
  
   - 
    
     
    
    
     
      // SpringApplication 代码片段
     
    
- 
    
     
    
    
     	
      private 
      void 
      prepareContext
      (ConfigurableApplicationContext context, 
     
    
- 
    
     
    
    
     
       ConfigurableEnvironment environment,
     
    
- 
    
     
    
    
     
       SpringApplicationRunListeners listeners, 
     
    
- 
    
     
    
    
     
       ApplicationArguments applicationArguments, 
     
    
- 
    
     
    
    
     
       Banner printedBanner) {
     
    
- 
    
     
    
    
            
      // 1. 关联环境信息对象到应用上下文对象 
     
    
- 
    
     
    
    
     
      		context.setEnvironment(environment);
     
    
- 
    
     
    
    
            
      // 2. 对象创建后置处理 : 设置容器的类型转换服务 
     
    
- 
    
     
    
    
     
      		postProcessApplicationContext(context);
     
    
- 
    
     
    
    
            
      // 3. 初始化应用上下文对象:调用各个 ApplicationContextInitializer 
     
    
- 
    
     
    
    
     
      		applyInitializers(context);
     
    
- 
    
     
    
    
            
      // 4. 广播事件 : ApplicationContextInitializedEvent 
     
    
- 
    
     
    
    
     
      		listeners.contextPrepared(context);
     
    
- 
    
     
    
    
     		
      if (
      this.logStartupInfo) {
     
    
- 
    
     
    
    
     
      			logStartupInfo(context.getParent() == 
      null);
     
    
- 
    
     
    
    
     
      			logStartupProfileInfo(context);
     
    
- 
    
     
    
    
     
      		}
     
    
- 
    
     
    
    
     		
      // Add boot specific singleton beans
     
    
- 
    
     
    
    
            
      // 5. 将应用程序参数作为一个 bean 注册到容器 : springApplicationArguments 
     
    
- 
    
     
    
    
     		
      ConfigurableListableBeanFactory 
      beanFactory 
      = context.getBeanFactory();
     
    
- 
    
     
    
    
     
      		beanFactory.registerSingleton(
      "springApplicationArguments", applicationArguments);
     
    
- 
    
     
    
    
     		
      if (printedBanner != 
      null) {
     
    
- 
    
     
    
    
     
      			beanFactory.registerSingleton(
      "springBootBanner", printedBanner);
     
    
- 
    
     
    
    
     
      		}
     
    
- 
    
     
    
    
     		
      if (beanFactory 
      instanceof DefaultListableBeanFactory) {
     
    
- 
    
     
    
    
     
      			((DefaultListableBeanFactory) beanFactory)
     
    
- 
    
     
    
    
     
      					.setAllowBeanDefinitionOverriding(
      this.allowBeanDefinitionOverriding);
     
    
- 
    
     
    
    
     
      		}
     
    
- 
    
     
    
    
             
     
    
- 
    
     
    
    
     		
      // 获取主启动类的路径
     
    
- 
    
     
    
    
     
      		Set<Object> sources = getAllSources();
     
    
- 
    
     
    
    
     
      		Assert.notEmpty(sources, 
      "Sources must not be empty");
     
    
- 
    
     
    
    
            
      // 6. 将主启动类封装成一个BeanDefinition 
     
    
- 
    
     
    
    
     
      		load(context, sources.toArray(
      new 
      Object[
      0]));
     
    
- 
    
     
    
    
            
      // 7. 上下文加载完成生命周期事件回调,为各个实现了 接口 ApplicationContextAware 的 
     
    
- 
    
     
    
    
            
      // ApplicationListener 设置应用上下文对象属性, 并广播事件 : ApplicationPreparedEvent 
     
    
- 
    
     
    
    
     
      		listeners.contextLoaded(context);
     
    
- 
    
     
    
    
     
      	}
     
    
 3.4.2.刷新
主要是调用应用上下文对象 ApplicationContext 自身的 refresh 方法,这是上下文对象的初始化中最关键的一步,该步骤中会完成几个核心动作:
-  初始化IOC容器(即BeanFactory) 该步骤中就会扫描解析注解,触发自动装配. 
-  初始化WebServer容器 
刷新应用上下文的动作其实是在spring相关的jar中,因此首先要有个概念,在这一步之前spring boot的动作已经完成,真正与IOC相关的动作还是由spring来完成,所以说spring boot是对spring的二次封装。
  
   - 
    
     
    
    
     
      public 
      void 
      refresh
      () 
      throws BeansException, IllegalStateException {
     
    
- 
    
     
    
    
     		
      synchronized (
      this.startupShutdownMonitor) {
     
    
- 
    
     
    
    
     			
      // 做一些初始化动作
     
    
- 
    
     
    
    
     
      			prepareRefresh();
     
    
- 
    
     
    
    
     			
      // 获取bean factory
     
    
- 
    
     
    
    
     			
      ConfigurableListableBeanFactory 
      beanFactory 
      = obtainFreshBeanFactory();
     
    
- 
    
     
    
    
     			
      // 初始化bean factory,为其成员属性赋一些值
     
    
- 
    
     
    
    
     
      			prepareBeanFactory(beanFactory);
     
    
- 
    
     
    
    
     			
      try {
     
    
- 
    
     
    
    
     				
      // 获取所有bean后置处理器
     
    
- 
    
     
    
    
     
      				postProcessBeanFactory(beanFactory);
     
    
- 
    
     
    
    
     				
      // **最核心的方法,注解的扫描,自动配置类的装载,IOC的初始化等全在这个方法中
     
    
- 
    
     
    
    
     
      				invokeBeanFactoryPostProcessors(beanFactory);
     
    
- 
    
     
    
    
     				
      // Register bean processors that intercept bean creation.
     
    
- 
    
     
    
    
     
      				registerBeanPostProcessors(beanFactory);
     
    
- 
    
     
    
    
     				
      // Initialize message source for this context.
     
    
- 
    
     
    
    
     
      				initMessageSource();
     
    
- 
    
     
    
    
     				
      // Initialize event multicaster for this context.
     
    
- 
    
     
    
    
     
      				initApplicationEventMulticaster();
     
    
- 
    
     
    
    
     				
      // Initialize other special beans in specific context subclasses.
     
    
- 
    
     
    
    
     
      				onRefresh();
     
    
- 
    
     
    
    
     				
      // Check for listener beans and register them.
     
    
- 
    
     
    
    
     
      				registerListeners();
     
    
- 
    
     
    
    
     				
      // Instantiate all remaining (non-lazy-init) singletons.
     
    
- 
    
     
    
    
     
      				finishBeanFactoryInitialization(beanFactory);
     
    
- 
    
     
    
    
     				
      // Last step: publish corresponding event.
     
    
- 
    
     
    
    
     
      				finishRefresh();
     
    
- 
    
     
    
    
     
      			}
     
    
- 
    
     
    
    
     			
      catch (BeansException ex) {
     
    
- 
    
     
    
    
     				
      if (logger.isWarnEnabled()) {
     
    
- 
    
     
    
    
     
      					logger.warn(
      "Exception encountered during context initialization - " +
     
    
- 
    
     
    
    
     							
      "cancelling refresh attempt: " + ex);
     
    
- 
    
     
    
    
     
      				}
     
    
- 
    
     
    
    
      
     
    
- 
    
     
    
    
     				
      // Destroy already created singletons to avoid dangling resources.
     
    
- 
    
     
    
    
     
      				destroyBeans();
     
    
- 
    
     
    
    
      
     
    
- 
    
     
    
    
     				
      // Reset 'active' flag.
     
    
- 
    
     
    
    
     
      				cancelRefresh(ex);
     
    
- 
    
     
    
    
      
     
    
- 
    
     
    
    
     				
      // Propagate exception to caller.
     
    
- 
    
     
    
    
     				
      throw ex;
     
    
- 
    
     
    
    
     
      			}
     
    
- 
    
     
    
    
      
     
    
- 
    
     
    
    
     			
      finally {
     
    
- 
    
     
    
    
     				
      // Reset common introspection caches in Spring's core, since we
     
    
- 
    
     
    
    
     				
      // might not ever need metadata for singleton beans anymore...
     
    
- 
    
     
    
    
     
      				resetCommonCaches();
     
    
- 
    
     
    
    
     
      			}
     
    
- 
    
     
    
    
     
      		}
     
    
- 
    
     
    
    
     
      	}
     
    
 初始化IOC:
创建容器其实没有什么说的,就是new一个web server(tomcat、netty或者jetty)出来。这里着重要说一下初始化IOC。
入口在invokeBeanFactoryPostProcessors(beanFactory)。
IOC容器的初始化分为三步:
-  Resource定位 定位到需要的各种路径: -  BasePackage 这一步在准备刷新的时候就已经完成,并在封装在了主启动类封装为的BeanDefinition中。 基于BasePackage去扫描通过注解自定义的需要注入IOC的Bean。 
-  自动配置类的全路径 这一步在刷新应用上下文的时候进行,即去获取factory.properties。 基于自动配置类的全路径去将对应自动配置类注入IOC。 
 
-  
-  BeanDefinition载入 将定位到的Resource记录的Class分别封装为一个个的Definition。 
-  BeanDefinition注册 将Definition注册进IOC中。其实就是注入到一个ConcurrentHashMap中,IOC就是通过这个Map来持有这些BeanDefinition的。 
IOC涉及的两个核心概念:
-  BeanDefinition 
-  BeanFactory IOC容器其实就是BeanFactory,BeanFactory就是IOC容器的规范接口,有多个实现,最典型的就是DefalutListableBeanFactory,IOC容器中有一个成员Map(BeanDefinitionMap),该Map持有所有的BeanDefinition,用来维护Bean的基本信息(class、作用域等) 
转载:https://blog.csdn.net/Joker_ZJN/article/details/128708335
 
					