记:SpringBoot的自动配置 —源码如何处理加载条件和顺序

入口:AbstractApplicationContextrefresh方法

在其invokeBeanFactoryPostProcessors方法中,会找到所有需要加载的类,并且为之排序,根据类加载条件来放弃加载

@Override
public void refresh() throws BeansException, IllegalStateException {
   synchronized (this.startupShutdownMonitor) {
      // Prepare this context for refreshing.
      prepareRefresh();

      // Tell the subclass to refresh the internal bean factory.
      ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

      // Prepare the bean factory for use in this context.
      prepareBeanFactory(beanFactory);

      try {
         // Allows post-processing of the bean factory in context subclasses.
         postProcessBeanFactory(beanFactory);

         // Invoke factory processors registered as beans in the context.
          //在这里会找到所有需要加载的类(不仅仅是自动配置的类),并且为之排序,根据类加载条件来放弃加载
         invokeBeanFactoryPostProcessors(beanFactory);

AutoConfigurationImportSelectorgetCandidateConfigurations方法里读取所有自动配置类

通过SpringFactoriesLoaderloadFactoryNames方法,可以看见在loadSpringFactories里面读取META-INF/spring.factories配置

public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";
public static List<String> loadFactoryNames(Class<?> factoryClass, @Nullable ClassLoader classLoader) {
   String factoryClassName = factoryClass.getName();
   return loadSpringFactories(classLoader).getOrDefault(factoryClassName, Collections.emptyList());
}

private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {
   MultiValueMap<String, String> result = cache.get(classLoader);
   if (result != null) {
      return result;
   }

   try {
       //读取META-INF/spring.factories
      Enumeration<URL> urls = (classLoader != null ?
            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()) {
            String factoryClassName = ((String) entry.getKey()).trim();
            for (String factoryName : StringUtils.commaDelimitedListToStringArray((String) entry.getValue())) {
               result.add(factoryClassName, factoryName.trim());
            }
         }
      }
      cache.put(classLoader, result);
      return result;
   }
   catch (IOException ex) {
      throw new IllegalArgumentException("Unable to load factories from location [" +
            FACTORIES_RESOURCE_LOCATION + "]", ex);
   }
}

接着在AutoConfigurationSorterdoSortByAfterAnnotation方法里实现自动配置类的加载顺序

private void doSortByAfterAnnotation(AutoConfigurationClasses classes,
      List<String> toSort, Set<String> sorted, Set<String> processing,
      String current) {
   if (current == null) {
      current = toSort.remove(0);
   }
   processing.add(current);
   for (String after : classes.getClassesRequestedAfter(current)) {
      Assert.state(!processing.contains(after),
            "AutoConfigure cycle detected between " + current + " and " + after);
      if (!sorted.contains(after) && toSort.contains(after)) {
         doSortByAfterAnnotation(classes, toSort, sorted, processing, after);
      }
   }
   processing.remove(current);
   sorted.add(current);
}

然后在ConditionEvaluatorshouldSkip方法里处理@ConditionalXXX条件,决定类是否能被加载

public boolean shouldSkip(@Nullable AnnotatedTypeMetadata metadata, @Nullable ConfigurationPhase phase) {
   if (metadata == null || !metadata.isAnnotated(Conditional.class.getName())) {
      return false;
   }

   if (phase == null) {
      if (metadata instanceof AnnotationMetadata &&
            ConfigurationClassUtils.isConfigurationCandidate((AnnotationMetadata) metadata)) {
         return shouldSkip(metadata, ConfigurationPhase.PARSE_CONFIGURATION);
      }
      return shouldSkip(metadata, ConfigurationPhase.REGISTER_BEAN);
   }

   List<Condition> 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) && !condition.matches(this.context, metadata)) {
         return true;
      }
   }
    
   return false;
}

注意:
即便是使用@AutoConfigurationBefore/After,只是给正常等待创建的bean对应的beandefinition排序,最终可能因为种种原因,导致bean的真实加载顺序不与注解一致,比如,tomcat的初始化,可能引发健康检查的bean提前被创建,而其中这个健康检查的bean引用了一个需要特定顺序创建的bean(暂且叫specialBean)时,specialBean的顺序会被打乱,提前创建!!!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值