SpringBoot 自动装配

SpringBoot 启动过程

  1. SpringApplication的初始化模块,配置一些基本的环境变量、资源、构造器、监听器
  2. 实现了应用具体的启动方案,包括启动流程的监听模块、加载配置环境模块、及核心的创建上下文环境模块
  3. 自动化配置模块,该模块作为springboot自动配置核心

启动类上的注解:

@SpringBootApplication

  • @EnableAutoConfiguration:根据应用所生命的依赖来对Spring框架进行自动配置
    • @AutoConfigurationPackages:注册当前同级以及子级的包中的符合条件(如@Configuration)的bean的定义
    • @Import(AutoConfigurationImportSelector.class)扫描各个组件jar META-INF目录下的spirng.factories文件,将下面的包名.类名中的工程类全部进行加载到IOC容器中
  • @SpringBootConfiguration(内部@Configuration)等于在spring的xml配置文件(applicationContext.xml)中,装配所有bean事务,提供了一个spring的上下文环境
  • @ComoonentScan:子健扫描,自动发现和装配bean。默认扫描启动类所在的包路径下文件,所以要把启动类放在根包路径。

@ImportResource(加载xml文件)

启动流程

1、创建了应用的监听器SpringApplicationRunListeners并开始监听

2、加载配置环境ConfigurableEnvironment,如果是web则会加载StandardEnvironment。

3、配置环境加入到监听器对象中

4、创建run方法的返回对象:ConfigurableApplicationContext(应用配置上下文)

5、prepareContext方法将listeners、environment、applicationArguments、banner等组件与上下文对象关联

6、refreshContext方法,即AbstractApplicationContext的refresh方法,完成后进行shutdown钩子的注册。并做了一些收尾工作返回了应用上下文对象。

自动化配置

img
  • AutoConfigurationImportSelector,通过@Import导入到Spring容器,提供了selectImports方法,将所有需要导入的组件以全类名的方式返回。

    • selectImports方法中有一个getCandidateConfigurations方法,调用了SpringFactoriesLoader.loadFactoryNames方法。

      public String[] selectImports(AnnotationMetadata metadata) {
        if (!this.isEnabled(metadata)) {
              return NO_IMPORTS;
        } else {
          try {
            //获取 @EnableAutoConfigoration 标注类的元信息,也就是获取该注解 exclude、excludeName 属性值
            AnnotationAttributes attributes = this.getAttributes(metadata);
            //获取META-INF/spring.factories文件下自动装配的类名集合
            List configurations = this.getCandidateConfigurations(metadata, attributes);
            //去除重复的自动装配组件,就是将List转为Set进行去重
            configurations = this.removeDuplicates(configurations);
            //这部分就是根据上面获取的 exclude 及 excludeName 属性值,排除指定的类
            Set exclusions = this.getExclusions(metadata, attributes);
            //删除对应的例外配置
            configurations.removeAll(exclusions);
            //排序,因为自动配置会有bean引用依赖,先按字母排序,再根据order排序,再根据ConfigurationBefore等排序
            configurations = this.sort(configurations);
            //输出满足条件的配置项目
            this.recordWithConditionEvaluationReport(configurations, exclusions);
            return (String[])configurations.toArray(new String[configurations.size()]);
          } catch (IOException var5) {
            throw new IllegalStateException(var5);
          }
        }
      }
      
  • SpringFacotiesLoader:工厂加载器,提供了loadFactoryNames方法,入参为factoryClass和classLoader,调用loadSpringFactories方法,会扫描所有jar包类路径下META-INF/spring.factories文件的内容,即根据@EnableAutoConfiguration的完整类名org.springframework.boot.autoconfigure.EnableAutoConfiguration作为查找的Key,获取对应的一组@Configuration类,包装成properties对象,获取到EnableAutoConfiguration的实现类的全限定名,反射实例化后添加到IOC容器中。

    • public static List loadFactoryNames(Class factoryClass, @Nullable ClassLoader classLoader) {
              String factoryClassName = factoryClass.getName();
              return loadSpringFactories(classLoader).getOrDefault(factoryClassName, Collections.emptyList());
          }
      
          private static Map> loadSpringFactories(@Nullable ClassLoader classLoader) {
              MultiValueMap result = cache.get(classLoader);
              if (result != null)
                  return result;
              try {
                  Enumeration urls = (classLoader != null ?
                  //META-INF/spring.factories
                          classLoader.getResources(FACTORIES_RESOURCE_LOCATION) :
                          ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));
                  result = new LinkedMultiValueMap<>();
                  while (urls.hasMoreElements()) {
                      URL url = urls.nextElement();
                      UrlResource resource = new UrlResource(url);
                      Properties properties = PropertiesLoaderUtils.loadProperties(resource);
                      for (Map.Entry entry : properties.entrySet()) {
                          List factoryClassNames = Arrays.asList(
                                  StringUtils.commaDelimitedListToStringArray((String) entry.getValue()));
                          result.addAll((String) entry.getKey(), factoryClassNames);
                      }
                  }
                  cache.put(classLoader, result);
                  return result;
              }
              catch (IOException ex) {
                  throw new IllegalArgumentException("Unable to load factories from location [" +
                          FACTORIES_RESOURCE_LOCATION + "]", ex);
              }
          }
      
  • 对每一个自动配置类进行自动配置功能,通过properties前缀来获取该配置类的配置项

  • 在 Spring Boot 项目中,我们将大量的参数配置在 application.properties 或 application.yml 文件中,通过@ConfigurationProperties 注解,我们可以获取这些参数值

你可能感兴趣的:(SpringBoot 自动装配)