SpringBoot之自动配置原理简要理解

自动配置原理

  1. @SpringBootApplication springboot应用程序入口

    • @SpringBootConfiguration

      声明此注解为springboot配置文件

    • @EnableAutoConfiguration

      自动配置注解

    • @ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
      @Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })

      对包进行扫描,把组件加入容器中

  2. @EnableAutoConfiguration

    • @Import(AutoConfigurationImportSelector.class)

      • AutoConfigurationImportSelector.class

        • selectImports方法

          @Override
          public String[] selectImports(AnnotationMetadata annotationMetadata) {
              if (!isEnabled(annotationMetadata)) {
                  return NO_IMPORTS;
              }
              
              AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(annotationMetadata);
              
              return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
          }
          
        • getAutoConfigurationEntry 获取配置条目=入口

          protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {
              if (!isEnabled(annotationMetadata)) {
                  return EMPTY_ENTRY;
              }
              AnnotationAttributes attributes = getAttributes(annotationMetadata);
              
              List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
              
              configurations = removeDuplicates(configurations);
              Set<String> exclusions = getExclusions(annotationMetadata, attributes);
              checkExcludedClasses(configurations, exclusions);
              configurations.removeAll(exclusions);
              configurations = getConfigurationClassFilter().filter(configurations);
              fireAutoConfigurationImportEvents(configurations, exclusions);
              return new AutoConfigurationEntry(configurations, exclusions);
          }
          
        • getCandidateConfigurations 获取候选的配置

          protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
              
              //获取到全部的配置类,也就是value值
              List<String> configurations = SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(),
                                                                                   getBeanClassLoader());
              Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring.factories. If you "
                              + "are using a custom packaging, make sure that file is correct.");
              return configurations;
          }
          

          在这里插入图片描述

  • loadFactoryNames

    public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) {
        ClassLoader classLoaderToUse = classLoader;
        if (classLoaderToUse == null) {
            classLoaderToUse = SpringFactoriesLoader.class.getClassLoader();
        }
        String factoryTypeName = factoryType.getName();
        return loadSpringFactories(classLoaderToUse).getOrDefault(factoryTypeName, Collections.emptyList());
    }
    
  • loadSpringFactories

    private static Map<String, List<String>> loadSpringFactories(ClassLoader classLoader) {
        Map<String, List<String>> result = cache.get(classLoader);
        if (result != null) {
            return result;
        }
    
        result = new HashMap<>();
        try {
            Enumeration<URL> urls = classLoader.getResources(FACTORIES_RESOURCE_LOCATION);
            while (urls.hasMoreElements()) {
                URL url = urls.nextElement();
                UrlResource resource = new UrlResource(url);
                //获取对于路径下的全部资源 key-value形式,此时value可有多个值 META-INF/spring.factories
                Properties properties = PropertiesLoaderUtils.loadProperties(resource);
                
                //将value放入到List result的key还是原来的key值,result的value为存放资源value的List
                for (Map.Entry<?, ?> entry : properties.entrySet()) {
                    String factoryTypeName = ((String) entry.getKey()).trim();
                    String[] factoryImplementationNames =
                        StringUtils.commaDelimitedListToStringArray((String) entry.getValue());
                    for (String factoryImplementationName : factoryImplementationNames) {
                        result.computeIfAbsent(factoryTypeName, key -> new ArrayList<>())
                            .add(factoryImplementationName.trim());
                    }
                }
            }
    
            // Replace all lists with unmodifiable lists containing unique elements
            result.replaceAll((factoryType, implementations) -> implementations.stream().distinct()
                              .collect(Collectors.collectingAndThen(Collectors.toList(), Collections::unmodifiableList)));
            cache.put(classLoader, result);
        }
        catch (IOException ex) {
            throw new IllegalArgumentException("Unable to load factories from location [" +
                                               FACTORIES_RESOURCE_LOCATION + "]", ex);
        }
        return result;
    }
    

    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

  • FACTORIES_RESOURCE_LOCATION

    public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";
    
  • 自动配置失效

    • 扫描@ConditionalXXX注解来判断是否放弃使用已有的配置而使用配置文件的配置

      @Conditional扩展注解作用(判断当前条件是否满足)
      @ConditionalOnJava系统的java版本是否符合要求
      @ConditionalOnBean容器中是否存在指定的Bean
      @ConditionalOnMissingBean容器中不存在指定的类
      @ConditionalOnExpression满足SpEL表达式指定规范
      @ConditionalOnClass在系统中有指定的对应的类
      @ConditionalOnMissingClass在系统中没有指定对应的类
      @ConditionalOnSingleCandidate容器中是否指定一个单实例的Bean,或者找个是一个首选的Bean
      @ConditionalOnProperty系统中指定的对应的属性是否有对应的值
      @ConditionalOnResource类路径下是否存在指定的资源文件
      @ConditionalOnWebApplication当前是Web环境
      @ConditionalOnNotWebApplication当前不是Web环境
      @ConditionalOnJndiJNDI存在指定项
      @Bean
      @ConditionalOnMissingBean(HiddenHttpMethodFilter.class)
      @ConditionalOnProperty(prefix = "spring.mvc.hiddenmethod.filter", name = "enabled")
      public OrderedHiddenHttpMethodFilter hiddenHttpMethodFilter() {
          return new OrderedHiddenHttpMethodFilter();
      }
      
      @Bean
      @ConditionalOnMissingBean(FormContentFilter.class)
      //在系统配置文件(application.yml)中是否有配置spring.mvc.formcontent.filter,如果有,将不会执行下面的配置,而使用系统配置文件中的配置
      @ConditionalOnProperty(prefix = "spring.mvc.formcontent.filter", name = "enabled", matchIfMissing = true)
      public OrderedFormContentFilter formContentFilter() {
          return new OrderedFormContentFilter();
      }
      
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值