19、Spring源码分析:ConfigurationClassPostProcessor

1、ConfigurationClassPostProcessor如何应用

ConfigurationClassPostProcessor在Spring启动时为我们自动注册的

  • 当我们使用了XmlWebApplicationContext并在配置文件中配置了<context:annotation-config/><context:component-scan/>元素,XmlWebApplicationContext的loadBeanDefinitions()方法会使用XmlBeanDefinitionReader.loadBeanDefinitions(Resource) 方法在内部注册一个ConfigurationClassPostProcessor的BeanDefinition。
  • 当使用AnnotationConfigWebApplicationContext时在loadBeanDefinitions方法被调用时会使用ClassPathBeanDefinitionScanner.scan()方法注册一个ConfigurationClassPostProcessor的BeanDefinition。
  • 当使用的是AnnotationConfigApplicationContext会在scan(String...)方法被调用时注册ConfigurationClassPostProcessor的BeanDefinition。

以上三种注册ConfigurationClassPostProcessor的方式都是使用了AnnotationConfigUtils的静态方法registerAnnotationConfigProcessors()。

2、postProcessBeanDefinitionRegistry()原理分析

ConfigurationClassPostProcessor是BeanDefinitionRegistryPostProcessor的实现类,用来解析被@Configuration,@Component,@ComponentScan,@Import,@ImportResource标记的类,在postProcessBeanDefinitionRegistry()方法执行阶段会将进一步从被@Configuration标记的类上面寻找BeanDefintion注册到容器中。

@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
   int registryId = System.identityHashCode(registry);
   if (this.registriesPostProcessed.contains(registryId)) {
      throw new IllegalStateException(
            "postProcessBeanDefinitionRegistry already called on this post-processor against " + registry);
   }
   if (this.factoriesPostProcessed.contains(registryId)) {
      throw new IllegalStateException(
            "postProcessBeanFactory already called on this post-processor against " + registry);
   }
   //保存处理过的registry,避免重复处理
   this.registriesPostProcessed.add(registryId);
   //处理java bean配置形式的bean定义
   processConfigBeanDefinitions(registry);
}
public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
   List<BeanDefinitionHolder> configCandidates = new ArrayList<>();
   //取出容器中已经存在的所有bean 定义
   String[] candidateNames = registry.getBeanDefinitionNames();
   //判断每个bean定义是否是ConfigurationClass(被@Configuration,@Component,@ComponentScan,@Import,@ImportResource标记的),
   //如果是则会给这个bean definition增加一个属性,避免重复解析
   for (String beanName : candidateNames) {
      BeanDefinition beanDef = registry.getBeanDefinition(beanName);
      // isFullConfigurationClass判断是否有full属性,isLiteConfigurationClass判断是否有lite属性
      // 首次判断都为false,下面分支checkConfigurationClassCandidate方法会赋值这个属性
      if (ConfigurationClassUtils.isFullConfigurationClass(beanDef) ||
            ConfigurationClassUtils.isLiteConfigurationClass(beanDef)) {
         if (logger.isDebugEnabled()) {
            logger.debug("Bean definition has already been processed as a configuration class: " + beanDef);
         }
      }
      //如果符合一个配置类型的java类定义,带有@Configuration为full
      //带有@Component、@ComponentScan、@Import、@ImportResource之一或方法上有@Bean为lite
      //加入configCandidates集合,后面根据优先级实例化配置bean
      else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {
         configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));
      }
   }

   // Return immediately if no @Configuration classes were found
   if (configCandidates.isEmpty()) {
      return;
   }

   // Sort by previously determined @Order value, if applicable
   configCandidates.sort((bd1, bd2) -> {
      int i1 = ConfigurationClassUtils.getOrder(bd1.getBeanDefinition());
      int i2 = ConfigurationClassUtils.getOrder(bd2.getBeanDefinition());
      return Integer.compare(i1, i2);
   });

   // Detect any custom bean name generation strategy supplied through the enclosing application context
   SingletonBeanRegistry sbr = null;
   if (registry instanceof SingletonBeanRegistry) {
      sbr = (SingletonBeanRegistry) registry;
      if (!this.localBeanNameGeneratorSet) {
         //如果AnnotationConfigWebApplicationContext设置了beanNameGenerator,则使用该beanNameGenerator
         //否则组件扫描bean name是简单类名首字母小写,被导入的bean name是类的全限定名
         BeanNameGenerator generator = (BeanNameGenerator) sbr.getSingleton(CONFIGURATION_BEAN_NAME_GENERATOR);
         if (generator != null) {
            this.componentScanBeanNameGenerator = generator;
            this.importBeanNameGenerator = generator;
         }
      }
   }

   if (this.environment == null) {
      this.environment = new StandardEnvironment();
   }

   // Parse each @Configuration class
   //用于将被注解的类转换成ConfigurationClass供ConfigurationClassBeanDefinitionReader注册
   ConfigurationClassParser parser = new ConfigurationClassParser(
         this.metadataReaderFactory, this.problemReporter, this.environment,
         this.resourceLoader, this.componentScanBeanNameGenerator, registry);

   Set<BeanDefinitionHolder> candidates = new LinkedHashSet<>(configCandidates);
   Set<ConfigurationClass> alreadyParsed = new HashSet<>(configCandidates.size());
   //解析一个ConfigurationClass后可能产生新的ConfigurationClass definition需要循环处理
   do {
      //解析ConfigurationClass的过程
      parser.parse(candidates);
      //@Configuration类不允许是final的,因为需要使用CGLIB生成代理对象,见postProcessBeanFactory方法。
      //@Bean方法必须是可被重写的(可以是私有方法)静态方法不做处理
      parser.validate();
      //所有的配置类@Configuration
      Set<ConfigurationClass> configClasses = new LinkedHashSet<>(parser.getConfigurationClasses());
      configClasses.removeAll(alreadyParsed);

      // Read the model and create bean definitions based on its content
      if (this.reader == null) {
         this.reader = new ConfigurationClassBeanDefinitionReader(
               registry, this.sourceExtractor, this.resourceLoader, this.environment,
               this.importBeanNameGenerator, parser.getImportRegistry());
      }

      //将@Configuration @Import @ImportResource @ImportRegistrar注册为bean
      this.reader.loadBeanDefinitions(configClasses);
      alreadyParsed.addAll(configClasses);

      candidates.clear();
      if (registry.getBeanDefinitionCount() > candidateNames.length) {
         String[] newCandidateNames = registry.getBeanDefinitionNames();
         Set<String> oldCandidateNames = new HashSet<>(Arrays.asList(candidateNames));
         Set<String> alreadyParsedClasses = new HashSet<>();
         for (ConfigurationClass configurationClass : alreadyParsed) {
            alreadyParsedClasses.add(configurationClass.getMetadata().getClassName());
         }
         //如果有新的bean注册,判断是否符合配置类 进而继续解析
         for (String candidateName : newCandidateNames) {
            if (!oldCandidateNames.contains(candidateName)) {
               BeanDefinition bd = registry.getBeanDefinition(candidateName);
               if (ConfigurationClassUtils.checkConfigurationClassCandidate(bd, this.metadataReaderFactory) &&
                     !alreadyParsedClasses.contains(bd.getBeanClassName())) {
                  candidates.add(new BeanDefinitionHolder(bd, candidateName));
               }
            }
         }
         candidateNames = newCandidateNames;
      }
   }
   while (!candidates.isEmpty());

   // Register the ImportRegistry as a bean in order to support ImportAware @Configuration classes
   if (sbr != null && !sbr.containsSingleton(IMPORT_REGISTRY_BEAN_NAME)) {
      //ImportStack记录了哪些配置类通过@Import(看ImportSelector,ImportBeanDefinitionRegistrar接口)导入了哪些类
      //后面通过ImportAwareBeanPostProcessor的功能实现了ImportAware接口的配置类可以得到导入类的注解属性
      sbr.registerSingleton(IMPORT_REGISTRY_BEAN_NAME, parser.getImportRegistry());
   }

   if (this.metadataReaderFactory instanceof CachingMetadataReaderFactory) {
      // Clear cache in externally provided MetadataReaderFactory; this is a no-op
      // for a shared cache since it'll be cleared by the ApplicationContext.
      ((CachingMetadataReaderFactory) this.metadataReaderFactory).clearCache();
   }
}

配置类ConfigurationClass代表了一个用户定义的@Configuration注解的类,其中包含了其自身和祖先标有@Bean的方法。

final class ConfigurationClass {
   //带有该配置类注解信息的ClassMetadata,可获取类和类上面注解的信息
   private final AnnotationMetadata metadata;
   //类的来源
   private final Resource resource;
   //该类的bean name
   @Nullable
   private String beanName;
   //是被哪个配置类@Import的
   private final Set<ConfigurationClass> importedBy = new LinkedHashSet<>(1);
   //自身和祖先的@Bean方法
   private final Set<BeanMethod> beanMethods = new LinkedHashSet<>();
   //保存@ImportResource location与reader属性,后会使用reader解析location代表的资源转换一波配置类
   private final Map<String, Class<? extends BeanDefinitionReader>> importedResources =
         new LinkedHashMap<>();
   //@Import value属性是ImportBeanDefinitionRegistrar
   private final Map<ImportBeanDefinitionRegistrar, AnnotationMetadata> importBeanDefinitionRegistrars =
         new LinkedHashMap<>();
   //记录不满足@Conditional value属性指定接口的@Bean方法,因为子类重写方法可能不满足条件,固需要记录,解析到父类就可直接跳过
   final Set<String> skippedBeanMethods = new HashSet<>();
}

2.1、parse()方法解析

在看ConfigurationClassParser.parse()方法前先看看他的成员变量。

class ConfigurationClassParser {

   private static final PropertySourceFactory DEFAULT_PROPERTY_SOURCE_FACTORY = new DefaultPropertySourceFactory();

   private static final Comparator<DeferredImportSelectorHolder> DEFERRED_IMPORT_COMPARATOR =
         (o1, o2) -> AnnotationAwareOrderComparator.INSTANCE.compare(o1.getImportSelector(), o2.getImportSelector());
   private final Log logger = LogFactory.getLog(getClass());
   //构造器传入CachingMetadataReaderFactory
   private final MetadataReaderFactory metadataReaderFactory;
   //构造器传入FailFastProblemReporter
   private final ProblemReporter problemReporter;
   //容器传入
   private final Environment environment;
   //构造器传入DefaultResourceLoader
   private final ResourceLoader resourceLoader;
   //当前容器
   private final BeanDefinitionRegistry registry;
   //解析@ComponentScan
   private final ComponentScanAnnotationParser componentScanParser;
   //根据@Conditional注解指定的Condition接口来决定是否跳过此方法的解析
   private final ConditionEvaluator conditionEvaluator;
   //保存解析过的@Configuration类
   private final Map<ConfigurationClass, ConfigurationClass> configurationClasses = new LinkedHashMap<>();
   //保存被解析类父类,避免多个子类导致同一个父类被解析多次
   private final Map<String, ConfigurationClass> knownSuperclasses = new HashMap<>();
   //保存@PropertySource指定的资源
   private final List<String> propertySourceNames = new ArrayList<>();
   //保存@Import导入的类 key是正在解析的 value是被导入的
   private final ImportStack importStack = new ImportStack();
   //保存当@Import指定的是DeferredImportSelector,这类延迟解析 见parse方法
   private final DeferredImportSelectorHandler deferredImportSelectorHandler = new DeferredImportSelectorHandler();

   public ConfigurationClassParser(MetadataReaderFactory metadataReaderFactory,
      ProblemReporter problemReporter, Environment environment, ResourceLoader resourceLoader,
      BeanNameGenerator componentScanBeanNameGenerator, BeanDefinitionRegistry registry) {

       this.metadataReaderFactory = metadataReaderFactory;
       this.problemReporter = problemReporter;
       this.environment = environment;
       this.resourceLoader = resourceLoader;
       this.registry = registry;
       this.componentScanParser = new ComponentScanAnnotationParser(
         environment, resourceLoader, componentScanBeanNameGenerator, registry);
       this.conditionEvaluator = new ConditionEvaluator(registry, environment, resourceLoader);
   }
}

ConfigurationClassParser.parse()方法解析配置类,parse()方法内部会统一调用processConfigurationClass()方法。

public void parse(Set<BeanDefinitionHolder> configCandidates) {
   for (BeanDefinitionHolder holder : configCandidates) {
      BeanDefinition bd = holder.getBeanDefinition();
      try {
         //首次调用parse()方法处理的是AnnotatedBeanDefinition,通过@ImportResource加载的xml资源会走下面两个分支
         if (bd instanceof AnnotatedBeanDefinition) {
            parse(((AnnotatedBeanDefinition) bd).getMetadata(), holder.getBeanName());
         }
         else if (bd instanceof AbstractBeanDefinition && ((AbstractBeanDefinition) bd).hasBeanClass()) {
            parse(((AbstractBeanDefinition) bd).getBeanClass(), holder.getBeanName());
         }
         else {
            parse(bd.getBeanClassName(), holder.getBeanName());
         }
      }
      catch (BeanDefinitionStoreException ex) {
         throw ex;
      }
      catch (Throwable ex) {
         throw new BeanDefinitionStoreException(
               "Failed to parse configuration class [" + bd.getBeanClassName() + "]", ex);
      }
   }
   //处理@Import指定的是DeferredImportSelector
   this.deferredImportSelectorHandler.process();
}
protected final void parse(@Nullable String className, String beanName) throws IOException {
   Assert.notNull(className, "No bean class name for configuration class bean definition");
   MetadataReader reader = this.metadataReaderFactory.getMetadataReader(className);
   processConfigurationClass(new ConfigurationClass(reader, beanName));
}

protected final void parse(Class<?> clazz, String beanName) throws IOException {
   processConfigurationClass(new ConfigurationClass(clazz, beanName));
}

protected final void parse(AnnotationMetadata metadata, String beanName) throws IOException {
   processConfigurationClass(new ConfigurationClass(metadata, beanName));
}

首先解析已存在的bean definition上的ConfigurationClass然后处理@Import指定的是DeferredImportSelector所返回的类。三个protected的parse()方法都是调用processConfigurationClass()方法,参数是ConfigurationClass对象。processConfigurationClass是真正处理@Configuration,此时还是不是将配置类注册为bean,而是通过此配置类继续找到其他的配置类,其他的配置类就属于被导入的配置类。

protected void processConfigurationClass(ConfigurationClass configClass) throws IOException {
   //根据@Conditional指定的Condition实现类match方法返回值决定是否跳过,具体看下面
   if (this.conditionEvaluator.shouldSkip(configClass.getMetadata(), ConfigurationPhase.PARSE_CONFIGURATION)) {
      return;
   }

   ConfigurationClass existingClass = this.configurationClasses.get(configClass);
   if (existingClass != null) {
      //如果本次解析的configClass早已解析过了(class name一样就属于一个configClass),
      //并且都是被导入的,则合并导入configClass的ConfigurationClass
      if (configClass.isImported()) {
         if (existingClass.isImported()) {
            existingClass.mergeImportedBy(configClass);
         }
         // Otherwise ignore new imported config class; existing non-imported class overrides it.
         return;
      }
      else {
         // Explicit bean definition found, probably replacing an import.
         // Let's remove the old one and go with the new one.
         //如果用户手动定义了一个ConfigurationClass,则去掉可能之前被自动@Import的类
         this.configurationClasses.remove(configClass);
         this.knownSuperclasses.values().removeIf(configClass::equals);
      }
   }

   // Recursively process the configuration class and its superclass hierarchy.
   // 递归处理配置类及其超类层次结构。
   SourceClass sourceClass = asSourceClass(configClass);
   do {
      //从配置类解析一切可能的bean形式,内部类,成员方法,@Import等,返回值为父类,
      //继续解析父类直到为null
      sourceClass = doProcessConfigurationClass(configClass, sourceClass);
   }
   while (sourceClass != null);

   this.configurationClasses.put(configClass, configClass);
}
//phase代表当前metadata属于哪个阶段,只有phase符合ConfigurationCondition,才会调用matches()方法
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;
}

processConfigurationClass()方法中将ConfigurationClass简单包装成一个SourceClass对象为了将被注解的类以统一的方式处理,而不用关心类是如何加载的,因为类中会保存AnnotationMetadata对象,这个对象会包含类以及类上注解的所有信息。AnnotationMetadata是一个接口实现类有AnnotationMetadataReadingVisitor和StandardAnnotationMetadata,前者的获取需要SimpleMetadataReader,后者需要一个Class对象,所以SourceClass的构造器需要传入一个MetadataReader或Class。

private class SourceClass implements Ordered {

   private final Object source;  // Class or MetadataReader

   private final AnnotationMetadata metadata;

   public SourceClass(Object source) {
      this.source = source;
      if (source instanceof Class) {
         this.metadata = new StandardAnnotationMetadata((Class<?>) source, true);
      }
      else {
         this.metadata = ((MetadataReader) source).getAnnotationMetadata();
      }
   }
}

doProcessConfigurationClass()方法会构建一个完整的ConfigurationClass对象,换句话说就是填充上面提过的ConfigurationClass的那些成员属性通过读取配置类的注解、成员类和方法。

@Nullable
protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass)
      throws IOException {
   //如果正在处理的类的注解层次机构里有@Component则会先处理它的成员内部类,具体看下面
   if (configClass.getMetadata().isAnnotated(Component.class.getName())) {
      // Recursively process any member (nested) classes first
      processMemberClasses(configClass, sourceClass);
   }

   // Process any @PropertySource annotations
   for (AnnotationAttributes propertySource : AnnotationConfigUtils.attributesForRepeatable(
         sourceClass.getMetadata(), PropertySources.class,
         org.springframework.context.annotation.PropertySource.class)) {
      if (this.environment instanceof ConfigurableEnvironment) {
         //将@PropertySource指定的properties资源合并到environment中,注意如果有多个@PropertySource命名相同name属性,
         //则会合并相同名字的资源文件.并且填充configClass的propertySourceNames属性
         processPropertySource(propertySource);
      }
      else {
         logger.info("Ignoring @PropertySource annotation on [" + sourceClass.getMetadata().getClassName() +
               "]. Reason: Environment must implement ConfigurableEnvironment");
      }
   }

   // Process any @ComponentScan annotations
   Set<AnnotationAttributes> componentScans = AnnotationConfigUtils.attributesForRepeatable(
         sourceClass.getMetadata(), ComponentScans.class, ComponentScan.class);
   if (!componentScans.isEmpty() &&
         !this.conditionEvaluator.shouldSkip(sourceClass.getMetadata(), ConfigurationPhase.REGISTER_BEAN)) {
      for (AnnotationAttributes componentScan : componentScans) {
         // The config class is annotated with @ComponentScan -> perform the scan immediately
         Set<BeanDefinitionHolder> scannedBeanDefinitions =
               this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());
         // Check the set of scanned definitions for any further config classes and parse recursively if needed
         for (BeanDefinitionHolder holder : scannedBeanDefinitions) {
            BeanDefinition bdCand = holder.getBeanDefinition().getOriginatingBeanDefinition();
            if (bdCand == null) {
               bdCand = holder.getBeanDefinition();
            }
            //有符合配置类的bean继续调用parse方法解析配置类重复doProcessConfigurationClass()的调用
            if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) {
               parse(bdCand.getBeanClassName(), holder.getBeanName());
            }
         }
      }
   }

   // Process any @Import annotations
   processImports(configClass, sourceClass, getImports(sourceClass), true);

   // Process any @ImportResource annotations
   // 一种静态批量注册bean的方式,不同于@Import可以指定三种形式,如@ImportResource("classpath:spring-dao.xml")
   AnnotationAttributes importResource =
         AnnotationConfigUtils.attributesFor(sourceClass.getMetadata(), ImportResource.class);
   if (importResource != null) {
      String[] resources = importResource.getStringArray("locations");
      Class<? extends BeanDefinitionReader> readerClass = importResource.getClass("reader");
      for (String resource : resources) {
         String resolvedResource = this.environment.resolveRequiredPlaceholders(resource);
         configClass.addImportedResource(resolvedResource, readerClass);
      }
   }

   // Process individual @Bean methods
   // 遵照方法的先后声明顺序
   Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(sourceClass);
   for (MethodMetadata methodMetadata : beanMethods) {
      configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
   }

   // Process default methods on interfaces
   // 支持接口默认方法的@Bean与普通类的@Bean没有区别
   processInterfaces(configClass, sourceClass);

   // Process superclass, if any
   if (sourceClass.getMetadata().hasSuperClass()) {
      String superclass = sourceClass.getMetadata().getSuperClassName();
      if (superclass != null && !superclass.startsWith("java") &&
            !this.knownSuperclasses.containsKey(superclass)) {
         this.knownSuperclasses.put(superclass, configClass);
         // Superclass found, return its annotation metadata and recurse
         return sourceClass.getSuperClass();
      }
   }

   // No superclass -> processing is complete
   return null;
}

doProcessConfigurationClass()方法用来解析配置类中的bean定义达到填充ConfigurationClass对象同时也会延展处理配置类,包括从以下几个方面来发现更多的配置类及bean:

1、 成员内部类;
2、 @ComponentScan注解指定包下扫描;
3、 @Import注解指定导入的类;
4、 @ImportResource指定的xml配置文件;
5、 @Bean标记的成员方法;
6、 @Bean标记接口默认方法;

2.1.1、内部类解析

找出成员内部类符合配置类的,调用processConfigurationClass()方法继续解析被发现的配置类。

//注册配置类里的成员类
private void processMemberClasses(ConfigurationClass configClass, SourceClass sourceClass) throws IOException {
   Collection<SourceClass> memberClasses = sourceClass.getMemberClasses();
   if (!memberClasses.isEmpty()) {
      List<SourceClass> candidates = new ArrayList<>(memberClasses.size());
      for (SourceClass memberClass : memberClasses) {
         //@Configuration @Component @ComponentScan @Import @ImportResource @Bean
         if (ConfigurationClassUtils.isConfigurationCandidate(memberClass.getMetadata()) &&
               !memberClass.getMetadata().getClassName().equals(configClass.getMetadata().getClassName())) {
            candidates.add(memberClass);
         }
      }
      //@Order注解排序
      OrderComparator.sort(candidates);
      for (SourceClass candidate : candidates) {
         //避免循环导入
         if (this.importStack.contains(configClass)) {
            //同一个类被多次导入抛BeanDefinitionParsingException
            this.problemReporter.error(new CircularImportProblem(configClass, this.importStack));
         }
         else {
            this.importStack.push(configClass);
            try {
               //可以看到对一个配置类的解析是先深度后广度
               processConfigurationClass(candidate.asConfigClass(configClass));
            }
            finally {
               this.importStack.pop();
            }
         }
      }
   }
}

2.1.2、合并@PropertySource指定的属性到Environment

private void processPropertySource(AnnotationAttributes propertySource) throws IOException {
   String name = propertySource.getString("name");
   if (!StringUtils.hasLength(name)) {
      name = null;
   }
   String encoding = propertySource.getString("encoding");
   if (!StringUtils.hasLength(encoding)) {
      encoding = null;
   }
   String[] locations = propertySource.getStringArray("value");
   Assert.isTrue(locations.length > 0, "At least one @PropertySource(value) location is required");
   boolean ignoreResourceNotFound = propertySource.getBoolean("ignoreResourceNotFound");

   Class<? extends PropertySourceFactory> factoryClass = propertySource.getClass("factory");
   PropertySourceFactory factory = (factoryClass == PropertySourceFactory.class ?
         DEFAULT_PROPERTY_SOURCE_FACTORY : BeanUtils.instantiateClass(factoryClass));

   for (String location : locations) {
      try {
         String resolvedLocation = this.environment.resolveRequiredPlaceholders(location);
         Resource resource = this.resourceLoader.getResource(resolvedLocation);
         addPropertySource(factory.createPropertySource(name, new EncodedResource(resource, encoding)));
      }
      catch (IllegalArgumentException | FileNotFoundException | UnknownHostException ex) {
         // Placeholders not resolvable or resource not found when trying to open it
         if (ignoreResourceNotFound) {
            if (logger.isInfoEnabled()) {
               logger.info("Properties location [" + location + "] not resolvable: " + ex.getMessage());
            }
         }
         else {
            throw ex;
         }
      }
   }
}

private void addPropertySource(PropertySource<?> propertySource) {
   String name = propertySource.getName();
   MutablePropertySources propertySources = ((ConfigurableEnvironment) this.environment).getPropertySources();

   if (this.propertySourceNames.contains(name)) {
      // We've already added a version, we need to extend it
      PropertySource<?> existing = propertySources.get(name);
      if (existing != null) {
         PropertySource<?> newSource = (propertySource instanceof ResourcePropertySource ?
               ((ResourcePropertySource) propertySource).withResourceName() : propertySource);
         if (existing instanceof CompositePropertySource) {
            ((CompositePropertySource) existing).addFirstPropertySource(newSource);
         }
         else {
            if (existing instanceof ResourcePropertySource) {
               existing = ((ResourcePropertySource) existing).withResourceName();
            }
            CompositePropertySource composite = new CompositePropertySource(name);
            composite.addPropertySource(newSource);
            composite.addPropertySource(existing);
            propertySources.replace(name, composite);
         }
         return;
      }
   }

   if (this.propertySourceNames.isEmpty()) {
      propertySources.addLast(propertySource);
   }
   else {
      String firstProcessed = this.propertySourceNames.get(this.propertySourceNames.size() - 1);
      propertySources.addBefore(firstProcessed, propertySource);
   }
   this.propertySourceNames.add(name);
}

2.1.3、解析@ComponentScan,扫描它指定的类或某些包范围下的类

将配置类中@ComponentScan注解指定的所有属性传递给ComponentScanAnnotationParser的parse方法,parse()方法的返回值为@ComponentScan扫描包下符合bean定义(默认为@Component)的BeanDefination,再次判断这些BeanDefination中是否有符合ConfigurationClassUtils.checkConfigurationClassCandidate()的,如果有再次调用parse()方法做深层次的解析。

关于这个方法的核心类ClassPathBeanDefinitionScanner请参考《Spring源码分析-ClassPathBeanDefinitionScanner》中有详细介绍。

public Set<BeanDefinitionHolder> parse(AnnotationAttributes componentScan, final String declaringClass) {
   //根据@ComponentScan的属性组装一个ClassPathBeanDefinitionScanner,由他负责扫描注册
   ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(this.registry,
         componentScan.getBoolean("useDefaultFilters"), this.environment, this.resourceLoader);

   Class<? extends BeanNameGenerator> generatorClass = componentScan.getClass("nameGenerator");
   boolean useInheritedGenerator = (BeanNameGenerator.class == generatorClass);
   scanner.setBeanNameGenerator(useInheritedGenerator ? this.beanNameGenerator :
         BeanUtils.instantiateClass(generatorClass));
   // 可以指定代理方式
   ScopedProxyMode scopedProxyMode = componentScan.getEnum("scopedProxy");
   if (scopedProxyMode != ScopedProxyMode.DEFAULT) {
      scanner.setScopedProxyMode(scopedProxyMode);
   }
   else {
      Class<? extends ScopeMetadataResolver> resolverClass = componentScan.getClass("scopeResolver");
      scanner.setScopeMetadataResolver(BeanUtils.instantiateClass(resolverClass));
   }

   scanner.setResourcePattern(componentScan.getString("resourcePattern"));

   for (AnnotationAttributes filter : componentScan.getAnnotationArray("includeFilters")) {
      for (TypeFilter typeFilter : typeFiltersFor(filter)) {
         scanner.addIncludeFilter(typeFilter);
      }
   }
   for (AnnotationAttributes filter : componentScan.getAnnotationArray("excludeFilters")) {
      for (TypeFilter typeFilter : typeFiltersFor(filter)) {
         scanner.addExcludeFilter(typeFilter);
      }
   }

   boolean lazyInit = componentScan.getBoolean("lazyInit");
   if (lazyInit) {
      scanner.getBeanDefinitionDefaults().setLazyInit(true);
   }

   Set<String> basePackages = new LinkedHashSet<>();
   String[] basePackagesArray = componentScan.getStringArray("basePackages");
   for (String pkg : basePackagesArray) {
      //支持指定多个包 分隔符",; \t\n"
      String[] tokenized = StringUtils.tokenizeToStringArray(this.environment.resolvePlaceholders(pkg),
            ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS);
      Collections.addAll(basePackages, tokenized);
   }
   for (Class<?> clazz : componentScan.getClassArray("basePackageClasses")) {
      //支持指定Class所在的包
      basePackages.add(ClassUtils.getPackageName(clazz));
   }
   //如果没有指明扫描范围,则使用当前处理的SourceClass所在的包
   if (basePackages.isEmpty()) {
      basePackages.add(ClassUtils.getPackageName(declaringClass));
   }
   //因为当前的declaringClass早已解析完了,需要排除掉
   scanner.addExcludeFilter(new AbstractTypeHierarchyTraversingFilter(false, false) {
      @Override
      protected boolean matchClassName(String className) {
         return declaringClass.equals(className);
      }
   });
   return scanner.doScan(StringUtils.toStringArray(basePackages));
}

扫描重点是由ClassPathBeanDefinitionScanner完成的,这个类在之前的博文里已经详细介绍过,请看这篇《【Spring源码分析】-ClassPathBeanDefinitionScanner》 这里就不在啰嗦,到此为止知道他可以将@ComponentScan指定的包下面的类注册到容器就可以。

2.1.4、解析@Import注解

spring会找出配置类被标记@Import的所有注解,包括注解也被标记@Import的。

private Set<SourceClass> getImports(SourceClass sourceClass) throws IOException {
* *Set<SourceClass> imports = new LinkedHashSet<>();
* *Set<SourceClass> visited = new LinkedHashSet<>();
* *collectImports(sourceClass, imports, visited);
* *return imports;
}
private void collectImports(SourceClass sourceClass, Set<SourceClass> imports, Set<SourceClass> visited)
* * * throws IOException {
*
* *if (visited.add(sourceClass)) {
* * * for (SourceClass annotation : sourceClass.getAnnotations()) {
* * * * *String annName = annotation.getMetadata().getClassName();
* * * * *// 如果是非@Import的注解,也会继续向上查找此注解上的@Import
* * * * *if (!annName.startsWith("java") && !annName.equals(Import.class.getName())) {
* * * * * * collectImports(annotation, imports, visited);
* * * * *}
* * * }
* * * // @Impor的value属性当做新的sourceClass,传递给下面的processImports方法
* * * imports.addAll(sourceClass.getAnnotationAttributes(Import.class.getName(), "value"));
* *}
}

处理@Import导入的类。

private void processImports(ConfigurationClass configClass, SourceClass currentSourceClass,
      Collection<SourceClass> importCandidates, boolean checkForCircularImports) {
   //@Import的value属性指定的class集合
   if (importCandidates.isEmpty()) {
      return;
   }
   //检查不能循环导入
   if (checkForCircularImports && isChainedImportOnStack(configClass)) {
      this.problemReporter.error(new CircularImportProblem(configClass, this.importStack));
   }
   else {
      this.importStack.push(configClass);
      try {
         for (SourceClass candidate : importCandidates) {
            if (candidate.isAssignable(ImportSelector.class)) {
               // Candidate class is an ImportSelector -> delegate to it to determine imports
               Class<?> candidateClass = candidate.loadClass();
               ImportSelector selector = BeanUtils.instantiateClass(candidateClass, ImportSelector.class);
               ParserStrategyUtils.invokeAwareMethods(
                     selector, this.environment, this.resourceLoader, this.registry);
               if (selector instanceof DeferredImportSelector) {
                  //如果是DeferredImportSelector,先不着急调用selectImports()方法,保存进deferredImportSelectorHandler中,在ConfigurationClassParser.parse()方法最后一步执行
                  this.deferredImportSelectorHandler.handle(
                        configClass, (DeferredImportSelector) selector);
               }
               else {
                  //如果是普通ImportSelector实现类,则立即调用selectImports()方法,返回值作为如果又是ImportSelector或ImportBeanDefinitionRegistrar
                  //则继续递归调用processImports(),知道返回值为非ImportSelector,走else分支
                  String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata());
                  Collection<SourceClass> importSourceClasses = asSourceClasses(importClassNames);
                  processImports(configClass, currentSourceClass, importSourceClasses, false);
               }
            }
            //如果是ImportBeanDefinitionRegistrar,先填充ConfigurationClass的importBeanDefinitionRegistrars属性,
            //在ConfigurationClassPostProcessor的processConfigBeanDefinitions()方法中ConfigurationClassParser的parse()方法结束后使用ConfigurationClassBeanDefinitionReader
            //的loadBeanDefinitions()方法中处理
            else if (candidate.isAssignable(ImportBeanDefinitionRegistrar.class)) {
               // Candidate class is an ImportBeanDefinitionRegistrar ->
               // delegate to it to register additional bean definitions
               Class<?> candidateClass = candidate.loadClass();
               ImportBeanDefinitionRegistrar registrar =
                     BeanUtils.instantiateClass(candidateClass, ImportBeanDefinitionRegistrar.class);
               ParserStrategyUtils.invokeAwareMethods(
                     registrar, this.environment, this.resourceLoader, this.registry);
               configClass.addImportBeanDefinitionRegistrar(registrar, currentSourceClass.getMetadata());
            }
            else {
               // Candidate class not an ImportSelector or ImportBeanDefinitionRegistrar ->
               // process it as an @Configuration class
               this.importStack.registerImport(
                     currentSourceClass.getMetadata(), candidate.getMetadata().getClassName());
               processConfigurationClass(candidate.asConfigClass(configClass));
            }
         }
      }
      catch (BeanDefinitionStoreException ex) {
         throw ex;
      }
      catch (Throwable ex) {
         throw new BeanDefinitionStoreException(
               "Failed to process import candidates for configuration class [" +
               configClass.getMetadata().getClassName() + "]", ex);
      }
      finally {
         this.importStack.pop();
      }
   }
}

@Import支持Class类型:

  • ImportSelector:如果是普通ImportSelector实现类,则立即调用selectImports()方法,返回值作为如果又是ImportSelector或ImportBeanDefinitionRegistrar。
  • ImportBeanDefinitionRegistrar:如果是DeferredImportSelector,先不着急调用selectImports()方法,保存进deferredImportSelectorHandler中,在ConfigurationClassParser.parse()方法最后一步执行
  • 普通类:当做ConfigurationClass继续调用ConfigurationClassParser.doProcessConfigurationClass()方法处理它。

2.1.5、解析@ImportResource注解

将locations指定的资源对象和reader指定的 BeanDefinitionReader保存到configClass中,后面会解析这些资源对象为bean。

AnnotationAttributes importResource =
      AnnotationConfigUtils.attributesFor(sourceClass.getMetadata(), ImportResource.class);
if (importResource != null) {
   String[] resources = importResource.getStringArray("locations");
   Class<? extends BeanDefinitionReader> readerClass = importResource.getClass("reader");
   for (String resource : resources) {
      String resolvedResource = this.environment.resolveRequiredPlaceholders(resource);
      configClass.addImportedResource(resolvedResource, readerClass);
   }
}

这段代码就是将@ImportResource属性locations指定的资源路径先保存在ConfigurationClass的importedResources属性中,然后也是同ImportBeanDefinitionRegistrar的处理时机在ConfigurationClassParser.parse()方法最后一步执行。这个资源解析交由reader属性指定的BeanDefinitionReader,默认使用XmlBeanDefinitionReader解析xml文件。

2.1.6、解析被@Bean标注的成员方法

将配置类标记@Bean注解的方法解析为MethodMetadata对象,随后将这些包装为BeanMethod保存到configClass中,然后统一注册为bean。

//检索当前SourceClass里所有@Bean方法
private Set<MethodMetadata> retrieveBeanMethodMetadata(SourceClass sourceClass) {
   AnnotationMetadata original = sourceClass.getMetadata();
   Set<MethodMetadata> beanMethods = original.getAnnotatedMethods(Bean.class.getName());
   //超过一个被@Bean的方法才需要排序,先后声明顺序
   if (beanMethods.size() > 1 && original instanceof StandardAnnotationMetadata) {
      // Try reading the class file via ASM for deterministic declaration order...
      // Unfortunately, the JVM's standard reflection returns methods in arbitrary
      // order, even between different runs of the same application on the same JVM.
      try {
         AnnotationMetadata asm =
               this.metadataReaderFactory.getMetadataReader(original.getClassName()).getAnnotationMetadata();
         Set<MethodMetadata> asmMethods = asm.getAnnotatedMethods(Bean.class.getName());
         if (asmMethods.size() >= beanMethods.size()) {
            Set<MethodMetadata> selectedMethods = new LinkedHashSet<>(asmMethods.size());
            for (MethodMetadata asmMethod : asmMethods) {
               for (MethodMetadata beanMethod : beanMethods) {
                  if (beanMethod.getMethodName().equals(asmMethod.getMethodName())) {
                     selectedMethods.add(beanMethod);
                     break;
                  }
               }
            }
            if (selectedMethods.size() == beanMethods.size()) {
               // All reflection-detected methods found in ASM method set -> proceed
               beanMethods = selectedMethods;
            }
         }
      }
      catch (IOException ex) {
         logger.debug("Failed to read class file via ASM for determining @Bean method order", ex);
         // No worries, let's continue with the reflection metadata we started with...
      }
   }
   return beanMethods;
}

上面代码的一段英文注释说,如果SourceClass的AnnotationMetadata是StandardAnnotationMetadata那就是使用了反射,反射获取类声明的方法顺序是不确定的,所以再尝试使用ASM框架它可以按方法声明的顺序得到方法声明,然后包装成MethodMetadata实例,StandardAnnotationMetadata包装的是StandardMethodMetadata,AnnotationMetadataReadingVisitor包装的是MethodMetadataReadingVisitor。MethodMetadata接口包含如下方法,可以方便获取方法的元数据。

public interface MethodMetadata extends AnnotatedTypeMetadata {
   String getMethodName();
   String getDeclaringClassName();
   String getReturnTypeName();
   boolean isAbstract();
   boolean isStatic();
   boolean isFinal();
   boolean isOverridable();
}

将retrieveBeanMethodMetadata()方法返回的集合填充进ConfigurationClass的beanMethods的属性中,后等待ConfigurationClassParser.parse()方法使用ConfigurationClassBeanDefinitionReader处理。

2.1.7、解析当前SourceClass接口的@Bean方法

这一步与第6步一样都是为了获取@Bean方法的抽象定义放入ConfigurationClass的beanMethods属性中,只不过java8后支持接口带有默认方法,这一步就是发现这些默认方法有@Bean的。

private void processInterfaces(ConfigurationClass configClass, SourceClass sourceClass) throws IOException {
   for (SourceClass ifc : sourceClass.getInterfaces()) {
      Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(ifc);
      for (MethodMetadata methodMetadata : beanMethods) {
         if (!methodMetadata.isAbstract()) {
            // A default method or other concrete method on a Java 8+ interface...
            configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
         }
      }
      processInterfaces(configClass, ifc);
   }
}

2.1.8、如果当前SourceClass还有父类,将父类走一遍上述流程。

if (sourceClass.getMetadata().hasSuperClass()) {
   String superclass = sourceClass.getMetadata().getSuperClassName();
   if (superclass != null && !superclass.startsWith("java") &&
         !this.knownSuperclasses.containsKey(superclass)) {
      this.knownSuperclasses.put(superclass, configClass);
      // Superclass found, return its annotation metadata and recurse
      return sourceClass.getSuperClass();
   }
}

到此为止经过ConfigurationClassParser.parse()方法已经将ConfigurationClass的属性都补全了(除了skippedBeanMethods),下面就是使用这些ConfigurationClass对象了。

2.2、validate()校验@Bean方法合法性

回到ConfigurationClassPostProcessor的processConfigBeanDefinitions()方法,得到ConfigurationClass对象后会使用validate()方法会做一个校验,配置类和@Bean方法不能是final的,因为需要使用CGLIB生成代理对象。

public void validate() {
* *for (ConfigurationClass configClass : this.configurationClasses.keySet()) {
* * * configClass.validate(this.problemReporter);
* *}
}
public void validate(ProblemReporter problemReporter) {
* *// A configuration class may not be final (CGLIB limitation)
* *if (getMetadata().isAnnotated(Configuration.class.getName())) {
* * * if (getMetadata().isFinal()) {
* * * * *problemReporter.error(new FinalConfigurationProblem());
* * * }
* *}
*
* *for (BeanMethod beanMethod : this.beanMethods) {
* * * beanMethod.validate(problemReporter);
* *}
}
public void validate(ProblemReporter problemReporter) {
* *if (getMetadata().isStatic()) {
* * * // static @Bean methods have no constraints to validate -> return immediately
* * * return;
* *}
*
* *if (this.configurationClass.getMetadata().isAnnotated(Configuration.class.getName())) {
* * * if (!getMetadata().isOverridable()) {
* * * * *// instance @Bean methods within @Configuration classes must be overridable to accommodate CGLIB
* * * * *problemReporter.error(new NonOverridableMethodError());
* * * }
* *}
}

2.3、processConfigBeanDefinitions()方法

校验ConfigurationClass对象合法性后会使用一个ConfigurationClassBeanDefinitionReader对象将这些ConfigurationClass解析为BeanDefiniton注册到容器中。下面看ConfigurationClassBeanDefinitionReader的唯一public方法loadBeanDefinitions()。

public void loadBeanDefinitions(Set<ConfigurationClass> configurationModel) {
   //处理@Conditional核心方法前面已经分析过了
   TrackedConditionEvaluator trackedConditionEvaluator = new TrackedConditionEvaluator();
   for (ConfigurationClass configClass : configurationModel) {
      loadBeanDefinitionsForConfigurationClass(configClass, trackedConditionEvaluator);
   }
}
private void loadBeanDefinitionsForConfigurationClass(
      ConfigurationClass configClass, TrackedConditionEvaluator trackedConditionEvaluator) {

   if (trackedConditionEvaluator.shouldSkip(configClass)) {
      String beanName = configClass.getBeanName();
      if (StringUtils.hasLength(beanName) && this.registry.containsBeanDefinition(beanName)) {
         this.registry.removeBeanDefinition(beanName);
      }
      this.importRegistry.removeImportingClass(configClass.getMetadata().getClassName());
      return;
   }
   //如果是被导入的类,则还没有注册为BeanDefiniton,则先将自身注册为BeanDefiniton,在注册属性代表的BeanDefinition
   if (configClass.isImported()) {
      registerBeanDefinitionForImportedConfigurationClass(configClass);
   }
   for (BeanMethod beanMethod : configClass.getBeanMethods()) {
      loadBeanDefinitionsForBeanMethod(beanMethod);
   }

   loadBeanDefinitionsFromImportedResources(configClass.getImportedResources());
   loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars());
}

private void registerBeanDefinitionForImportedConfigurationClass(ConfigurationClass configClass) {
   AnnotationMetadata metadata = configClass.getMetadata();
   AnnotatedGenericBeanDefinition configBeanDef = new AnnotatedGenericBeanDefinition(metadata);

   ScopeMetadata scopeMetadata = scopeMetadataResolver.resolveScopeMetadata(configBeanDef);
   configBeanDef.setScope(scopeMetadata.getScopeName());
   String configBeanName = this.importBeanNameGenerator.generateBeanName(configBeanDef, this.registry);
   AnnotationConfigUtils.processCommonDefinitionAnnotations(configBeanDef, metadata);

   BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(configBeanDef, configBeanName);
   definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
   this.registry.registerBeanDefinition(definitionHolder.getBeanName(), definitionHolder.getBeanDefinition());
   configClass.setBeanName(configBeanName);

   if (logger.isTraceEnabled()) {
      logger.trace("Registered bean definition for imported class '" + configBeanName + "'");
   }
}

2.3.1、注册@Bean方法为BeanDefinition。

private void loadBeanDefinitionsForBeanMethod(BeanMethod beanMethod) {
   ConfigurationClass configClass = beanMethod.getConfigurationClass();
   MethodMetadata metadata = beanMethod.getMetadata();
   String methodName = metadata.getMethodName();

   // Do we need to mark the bean as skipped by its condition?
   if (this.conditionEvaluator.shouldSkip(metadata, ConfigurationPhase.REGISTER_BEAN)) {
      configClass.skippedBeanMethods.add(methodName);
      return;
   }
   if (configClass.skippedBeanMethods.contains(methodName)) {
      return;
   }

   AnnotationAttributes bean = AnnotationConfigUtils.attributesFor(metadata, Bean.class);
   Assert.state(bean != null, "No @Bean annotation attributes");

   // Consider name and any aliases
   List<String> names = new ArrayList<>(Arrays.asList(bean.getStringArray("name")));
   String beanName = (!names.isEmpty() ? names.remove(0) : methodName);

   // Register aliases even when overridden
   for (String alias : names) {
      this.registry.registerAlias(beanName, alias);
   }

   // Has this effectively been overridden before (e.g. via XML)?
   if (isOverriddenByExistingDefinition(beanMethod, beanName)) {
      //如果容器中已经定义了同名的BeanDefiniton
      //同属于一个ConfigurationClass下直接抛异常
      //否则使用已定义好的,抛弃这个@Bean方法定义的
      if (beanName.equals(beanMethod.getConfigurationClass().getBeanName())) {
         throw new BeanDefinitionStoreException(beanMethod.getConfigurationClass().getResource().getDescription(),
               beanName, "Bean name derived from @Bean method '" + beanMethod.getMetadata().getMethodName() +
               "' clashes with bean name for containing configuration class; please make those names unique!");
      }
      return;
   }

   ConfigurationClassBeanDefinition beanDef = new ConfigurationClassBeanDefinition(configClass, metadata);
   beanDef.setResource(configClass.getResource());
   beanDef.setSource(this.sourceExtractor.extractSource(metadata, configClass.getResource()));

   if (metadata.isStatic()) {
      // static @Bean method
      beanDef.setBeanClassName(configClass.getMetadata().getClassName());
      beanDef.setFactoryMethodName(methodName);
   }
   else {
      // instance @Bean method
      beanDef.setFactoryBeanName(configClass.getBeanName());
      beanDef.setUniqueFactoryMethodName(methodName);
   }
   beanDef.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_CONSTRUCTOR);
   beanDef.setAttribute(org.springframework.beans.factory.annotation.RequiredAnnotationBeanPostProcessor.
         SKIP_REQUIRED_CHECK_ATTRIBUTE, Boolean.TRUE);
   //根据注解添加BeanDefinition属性@Lazy @Primary @DependsOn @Role @Description
   AnnotationConfigUtils.processCommonDefinitionAnnotations(beanDef, metadata);
   //自动装配模式 @Bean默认Autowire.NO
   Autowire autowire = bean.getEnum("autowire");
   if (autowire.isAutowire()) {
      beanDef.setAutowireMode(autowire.value());
   }
   //是否可以自动装配其他bean 默认true
   boolean autowireCandidate = bean.getBoolean("autowireCandidate");
   if (!autowireCandidate) {
      beanDef.setAutowireCandidate(false);
   }
   //@Bean也可指定创建bean的初始化方法
   String initMethodName = bean.getString("initMethod");
   if (StringUtils.hasText(initMethodName)) {
      beanDef.setInitMethodName(initMethodName);
   }

   String destroyMethodName = bean.getString("destroyMethod");
   beanDef.setDestroyMethodName(destroyMethodName);

   // Consider scoping
   ScopedProxyMode proxyMode = ScopedProxyMode.NO;
   AnnotationAttributes attributes = AnnotationConfigUtils.attributesFor(metadata, Scope.class);
   if (attributes != null) {
      beanDef.setScope(attributes.getString("value"));
      proxyMode = attributes.getEnum("proxyMode");
      if (proxyMode == ScopedProxyMode.DEFAULT) {
         proxyMode = ScopedProxyMode.NO;
      }
   }

   // Replace the original bean definition with the target one, if necessary
   BeanDefinition beanDefToRegister = beanDef;
   if (proxyMode != ScopedProxyMode.NO) {
      BeanDefinitionHolder proxyDef = ScopedProxyCreator.createScopedProxy(
            new BeanDefinitionHolder(beanDef, beanName), this.registry,
            proxyMode == ScopedProxyMode.TARGET_CLASS);
      beanDefToRegister = new ConfigurationClassBeanDefinition(
            (RootBeanDefinition) proxyDef.getBeanDefinition(), configClass, metadata);
   }

   if (logger.isTraceEnabled()) {
      logger.trace(String.format("Registering bean definition for @Bean method %s.%s()",
            configClass.getMetadata().getClassName(), beanName));
   }
   this.registry.registerBeanDefinition(beanName, beanDefToRegister);
}

上面有一点需要注意:如果此@Bean的proxyMode属性不是ScopedProxyMode.DEFAULT和ScopedProxyMode.NO,则需要使用代理技术创建一个新的BeanDefinition取代这个同名的BeanDefinition,将原来的重新命名也注册到容器中。看下面具体代码:

final class ScopedProxyCreator {

   private ScopedProxyCreator() {
   }
   public static BeanDefinitionHolder createScopedProxy(
         BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry, boolean proxyTargetClass) {

      return ScopedProxyUtils.createScopedProxy(definitionHolder, registry, proxyTargetClass);
   }

   public static String getTargetBeanName(String originalBeanName) {
      return ScopedProxyUtils.getTargetBeanName(originalBeanName);
   }

}
public abstract class ScopedProxyUtils {
   private static final String TARGET_NAME_PREFIX = "scopedTarget.";
   public static BeanDefinitionHolder createScopedProxy(BeanDefinitionHolder definition,
         BeanDefinitionRegistry registry, boolean proxyTargetClass) {

      String originalBeanName = definition.getBeanName();
      BeanDefinition targetDefinition = definition.getBeanDefinition();
      //原始bean重新命名scopedTarget.originalBeanName
      String targetBeanName = getTargetBeanName(originalBeanName);

      // Create a scoped proxy definition for the original bean name,
      // "hiding" the target bean in an internal target definition.
      //内部使用ProxyFactory创建代理对象,通过targetBeanName从容器获取目标对象
      RootBeanDefinition proxyDefinition = new RootBeanDefinition(ScopedProxyFactoryBean.class);
      proxyDefinition.setDecoratedDefinition(new BeanDefinitionHolder(targetDefinition, targetBeanName));
      proxyDefinition.setOriginatingBeanDefinition(targetDefinition);
      proxyDefinition.setSource(definition.getSource());
      proxyDefinition.setRole(targetDefinition.getRole());
      //代理类保存着原始类的bean name
      proxyDefinition.getPropertyValues().add("targetBeanName", targetBeanName);
      //代理目标类
      if (proxyTargetClass) {
         targetDefinition.setAttribute(AutoProxyUtils.PRESERVE_TARGET_CLASS_ATTRIBUTE, Boolean.TRUE);
         // ScopedProxyFactoryBean's "proxyTargetClass" default is TRUE, so we don't need to set it explicitly here.
      }
      //代理目标接口
      else {
         proxyDefinition.getPropertyValues().add("proxyTargetClass", Boolean.FALSE);
      }

      // Copy autowire settings from original bean definition.
      proxyDefinition.setAutowireCandidate(targetDefinition.isAutowireCandidate());
      proxyDefinition.setPrimary(targetDefinition.isPrimary());
      if (targetDefinition instanceof AbstractBeanDefinition) {
         proxyDefinition.copyQualifiersFrom((AbstractBeanDefinition) targetDefinition);
      }

      // The target bean should be ignored in favor of the scoped proxy.
      //避免使用容器里的原始类
      targetDefinition.setAutowireCandidate(false);
      targetDefinition.setPrimary(false);

      // Register the target bean as separate bean in the factory.
      registry.registerBeanDefinition(targetBeanName, targetDefinition);

      // Return the scoped proxy definition as primary bean definition
      // (potentially an inner bean).
      return new BeanDefinitionHolder(proxyDefinition, originalBeanName, definition.getAliases());
   }

   public static String getTargetBeanName(String originalBeanName) {
      return TARGET_NAME_PREFIX + originalBeanName;
   }

   public static boolean isScopedTarget(@Nullable String beanName) {
      return (beanName != null && beanName.startsWith(TARGET_NAME_PREFIX));
   }

}

2.3.2、注册@ImportResource指定资源代表的BeanDefinition

private void loadBeanDefinitionsFromImportedResources(
      Map<String, Class<? extends BeanDefinitionReader>> importedResources) {

   Map<Class<?>, BeanDefinitionReader> readerInstanceCache = new HashMap<>();

   importedResources.forEach((resource, readerClass) -> {
      // Default reader selection necessary?
      if (BeanDefinitionReader.class == readerClass) {
         if (StringUtils.endsWithIgnoreCase(resource, ".groovy")) {
            // When clearly asking for Groovy, that's what they'll get...
            readerClass = GroovyBeanDefinitionReader.class;
         }
         else {
            // Primarily ".xml" files but for any other extension as well
            readerClass = XmlBeanDefinitionReader.class;
         }
      }

      BeanDefinitionReader reader = readerInstanceCache.get(readerClass);
      if (reader == null) {
         try {
            // Instantiate the specified BeanDefinitionReader
            reader = readerClass.getConstructor(BeanDefinitionRegistry.class).newInstance(this.registry);
            // Delegate the current ResourceLoader to it if possible
            if (reader instanceof AbstractBeanDefinitionReader) {
               AbstractBeanDefinitionReader abdr = ((AbstractBeanDefinitionReader) reader);
               abdr.setResourceLoader(this.resourceLoader);
               abdr.setEnvironment(this.environment);
            }
            readerInstanceCache.put(readerClass, reader);
         }
         catch (Throwable ex) {
            throw new IllegalStateException(
                  "Could not instantiate BeanDefinitionReader class [" + readerClass.getName() + "]");
         }
      }

      // TODO SPR-6310: qualify relative path locations as done in AbstractContextLoader.modifyLocations
      reader.loadBeanDefinitions(resource);
   });
}

默认处理xml资源,也可以自定义BeanDefinitionReader解析任意资源完成bean的注册。

2.3.3、如果@Import指定的是ImportBeanDefinitionRegistrar可以完成批量注册

private void loadBeanDefinitionsFromRegistrars(Map<ImportBeanDefinitionRegistrar, AnnotationMetadata> registrars) {
   registrars.forEach((registrar, metadata) ->
         registrar.registerBeanDefinitions(metadata, this.registry));
}

参考org.springframework.context.annotation.AspectJAutoProxyRegistrar

3、postProcessBeanFactory()原理分析

到这为止对@Configuration类解析注册的过程就完成了,下面分析ConfigurationClassPostProcessor的postProcessBeanFactory()方法的,看看他他是如何增强@Configuration类的。

public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
   int factoryId = System.identityHashCode(beanFactory);
   if (this.factoriesPostProcessed.contains(factoryId)) {
      throw new IllegalStateException(
            "postProcessBeanFactory already called on this post-processor against " + beanFactory);
   }
   this.factoriesPostProcessed.add(factoryId);
   if (!this.registriesPostProcessed.contains(factoryId)) {
      // BeanDefinitionRegistryPostProcessor hook apparently not supported...
      // Simply call processConfigurationClasses lazily at this point then.
      processConfigBeanDefinitions((BeanDefinitionRegistry) beanFactory);
   }
   //加强@Configuration类
   enhanceConfigurationClasses(beanFactory);
   //此BeanPostProcessor会将实现了ImportAware接口的类注入ConfigurationClassParser的ImportStack
   beanFactory.addBeanPostProcessor(new ImportAwareBeanPostProcessor(beanFactory));
}

核心方法enhanceConfigurationClasses用来将标记@Configuration的配置类的BeanDefinition的beanClass替换为经过CGLIB加强过的,这样在实例化此bean的时候,就可以使用替换的代理类来创建对象了。

public void enhanceConfigurationClasses(ConfigurableListableBeanFactory beanFactory) {
* *Map<String, AbstractBeanDefinition> configBeanDefs = new LinkedHashMap<>();
* *for (String beanName : beanFactory.getBeanDefinitionNames()) {
* * * BeanDefinition beanDef = beanFactory.getBeanDefinition(beanName);
* * * //只增强@Configuration类
* * * if (ConfigurationClassUtils.isFullConfigurationClass(beanDef)) {
* * * * *//Spring提供的所有BeanDefinition的实现类都继承了AbstractBeanDefinition
* * * * *if (!(beanDef instanceof AbstractBeanDefinition)) {
* * * * * * throw new BeanDefinitionStoreException("Cannot enhance @Configuration bean definition '" +
* * * * * * * * * beanName + "' since it is not stored in an AbstractBeanDefinition subclass");
* * * * *}
* * * * *//如果已经存在了一个实例,那么不会增强它,造成这个现象的原因是@Bean方法的返回类型BeanDefinitionRegistryPostProcessor
* * * * *else if (logger.isInfoEnabled() && beanFactory.containsSingleton(beanName)) {
* * * * * * logger.info("Cannot enhance @Configuration bean definition '" + beanName +
* * * * * * * * * "' since its singleton instance has been created too early. The typical cause " +
* * * * * * * * * "is a non-static @Bean method with a BeanDefinitionRegistryPostProcessor " +
* * * * * * * * * "return type: Consider declaring such methods as 'static'.");
* * * * *}
* * * * *configBeanDefs.put(beanName, (AbstractBeanDefinition) beanDef);
* * * }
* *}
* *if (configBeanDefs.isEmpty()) {
* * * // nothing to enhance -> return immediately
* * * return;
* *}
* *//使用ConfigurationClassEnhancer增强配置类,使其拥有调用@Bean方法总是返回一个对象的能力
* *ConfigurationClassEnhancer enhancer = new ConfigurationClassEnhancer();
* *for (Map.Entry<String, AbstractBeanDefinition> entry : configBeanDefs.entrySet()) {
* * * AbstractBeanDefinition beanDef = entry.getValue();
* * * // If a @Configuration class gets proxied, always proxy the target class
* * * beanDef.setAttribute(AutoProxyUtils.PRESERVE_TARGET_CLASS_ATTRIBUTE, Boolean.TRUE);
* * * try {
* * * * *// Set enhanced subclass of the user-specified bean class
* * * * *Class<?> configClass = beanDef.resolveBeanClass(this.beanClassLoader);
* * * * *if (configClass != null) {
* * * * * * Class<?> enhancedClass = enhancer.enhance(configClass, this.beanClassLoader);
* * * * * * if (configClass != enhancedClass) {
* * * * * * * *if (logger.isTraceEnabled()) {
* * * * * * * * * logger.trace(String.format("Replacing bean definition '%s' existing class '%s' with " +
* * * * * * * * * * * * "enhanced class '%s'", entry.getKey(), configClass.getName(), enhancedClass.getName()));
* * * * * * * *}
* * * * * * * *beanDef.setBeanClass(enhancedClass);
* * * * * * }
* * * * *}
* * * }
* * * catch (Throwable ex) {
* * * * *throw new IllegalStateException("Cannot load configuration class: " + beanDef.getBeanClassName(), ex);
* * * }
* *}
}

ConfigurationClassEnhancer.enhance()方法会使用cglib返回配置类的一个代理类,这个代理类拦截了@Bean方法,重复调用这个方法总是返回同一个对象(默认行为,除非指定@Sope),使其拥有单例的能力。

public Class<?> enhance(Class<?> configClass, @Nullable ClassLoader classLoader) {
   if (EnhancedConfiguration.class.isAssignableFrom(configClass)) {
      if (logger.isDebugEnabled()) {
         logger.debug(String.format("Ignoring request to enhance %s as it has " +
               "already been enhanced. This usually indicates that more than one " +
               "ConfigurationClassPostProcessor has been registered (e.g. via " +
               "<context:annotation-config>). This is harmless, but you may " +
               "want check your configuration and remove one CCPP if possible",
               configClass.getName()));
      }
      return configClass;
   }
   Class<?> enhancedClass = createClass(newEnhancer(configClass, classLoader));
   if (logger.isTraceEnabled()) {
      logger.trace(String.format("Successfully enhanced %s; enhanced class name is: %s",
            configClass.getName(), enhancedClass.getName()));
   }
   return enhancedClass;
}

private Enhancer newEnhancer(Class<?> configSuperClass, @Nullable ClassLoader classLoader) {
   Enhancer enhancer = new Enhancer();
   enhancer.setSuperclass(configSuperClass);
   enhancer.setInterfaces(new Class<?>[] {EnhancedConfiguration.class});
   enhancer.setUseFactory(false);
   enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
   enhancer.setStrategy(new BeanFactoryAwareGeneratorStrategy(classLoader));
   enhancer.setCallbackFilter(CALLBACK_FILTER);
   enhancer.setCallbackTypes(CALLBACK_FILTER.getCallbackTypes());
   return enhancer;
}

private Class<?> createClass(Enhancer enhancer) {
   Class<?> subclass = enhancer.createClass();
   // Registering callbacks statically (as opposed to thread-local)
   // is critical for usage in an OSGi environment (SPR-5932)...
   Enhancer.registerStaticCallbacks(subclass, CALLBACKS);
   return subclass;
}

enhancer指定了父类为EnhancedConfiguration,此类实现了BeanFactoryAware接口,所以就拥有了setBeanFactory()方法因此Spring容器会将持有的BeanFactory通过此方法传递给代理对象。enhancer又配置了一个BeanFactoryAwareGeneratorStrategy,它会给代理类添加一个名为"$$beanFactory"并且类型为BeanFactory的字段。加上拦截器BeanFactoryAwareMethodInterceptor结合这三者,BeanFactoryAwareMethodInterceptor起作用的时候就会将$$beanFactory赋值为当前容器,而后代理对象就拥有了Spring容器。

public interface EnhancedConfiguration extends BeanFactoryAware { }

private static class BeanFactoryAwareGeneratorStrategy extends DefaultGeneratorStrategy {
   @Override
   protected ClassGenerator transform(ClassGenerator cg) throws Exception {
      ClassEmitterTransformer transformer = new ClassEmitterTransformer() {
         @Override
         public void end_class() {
            declare_field(Constants.ACC_PUBLIC, BEAN_FACTORY_FIELD, Type.getType(BeanFactory.class), null);
            super.end_class();
         }
      };
      return new TransformingClassGenerator(cg, transformer);
   }
}

enhancer还设置了一组拦截器(CALLBACKS),每当执行代理类的一个方法都会经过拦截器,至于选择哪个拦截器是由拦截器的isMatch()方法决定的,CALLBACKS是三个Callback实例,分别起到不同的作用。

private static final Callback[] CALLBACKS = new Callback[] {
      new BeanMethodInterceptor(),
      new BeanFactoryAwareMethodInterceptor(),
      NoOp.INSTANCE
};

当Spring容器调用目标对象的setBeanFactory()方法时,BeanFactoryAwareMethodInterceptor会拦截到,以为它的isMatch()犯法。

public boolean isMatch(Method candidateMethod) {
   return isSetBeanFactory(candidateMethod);
}

public static boolean isSetBeanFactory(Method candidateMethod) {
   return (candidateMethod.getName().equals("setBeanFactory") &&
         candidateMethod.getParameterCount() == 1 &&
         BeanFactory.class == candidateMethod.getParameterTypes()[0] &&
         BeanFactoryAware.class.isAssignableFrom(candidateMethod.getDeclaringClass()));
}

后执行拦截器的intercept()方法,此方法就是如上所说将BeanFactory保存到代理对象的$$beanFactory的属性,供代理对象使用,因为BeanMethodInterceptor生效的时候会用到。

如果调用目标对象的方法不是setBeanFactory()方法并且是@Bean方法则使用BeanMethodInterceptor加强(代理)此方法。值得注意的是当检查请求的bean是否是FactoryBean。如果是这样,创建一个子类代理来拦截对getObject()的调用并返回任何缓存的bean实例。作用域代理工厂bean是一种特殊情况,不应该进一步代理。

private static class BeanMethodInterceptor implements MethodInterceptor, ConditionalCallback {

   @Override
   @Nullable
   public Object intercept(Object enhancedConfigInstance, Method beanMethod, Object[] beanMethodArgs,
            MethodProxy cglibMethodProxy) throws Throwable {

      ConfigurableBeanFactory beanFactory = getBeanFactory(enhancedConfigInstance);
      String beanName = BeanAnnotationHelper.determineBeanNameFor(beanMethod);

      // Determine whether this bean is a scoped-proxy
      if (BeanAnnotationHelper.isScopedProxy(beanMethod)) {
         //获取被代理的目标bean的bean name  scopedTarget.beanName
         String scopedBeanName = ScopedProxyCreator.getTargetBeanName(beanName);
         if (beanFactory.isCurrentlyInCreation(scopedBeanName)) {
            beanName = scopedBeanName;
         }
      }

      // To handle the case of an inter-bean method reference, we must explicitly check the
      // container for already cached instances.

      // First, check to see if the requested bean is a FactoryBean. If so, create a subclass
      // proxy that intercepts calls to getObject() and returns any cached bean instance.
      // This ensures that the semantics of calling a FactoryBean from within @Bean methods
      // is the same as that of referring to a FactoryBean within XML. See SPR-6602.
      if (factoryContainsBean(beanFactory, BeanFactory.FACTORY_BEAN_PREFIX + beanName) &&
            factoryContainsBean(beanFactory, beanName)) {
         Object factoryBean = beanFactory.getBean(BeanFactory.FACTORY_BEAN_PREFIX + beanName);
         if (factoryBean instanceof ScopedProxyFactoryBean) {
            // Scoped proxy factory beans are a special case and should not be further proxied
            //如果我们显示的设置了@Scope属性proxyMode为代理模式,则不需要进一步代理了
         }
         else {
            // It is a candidate FactoryBean - go ahead with enhancement
            return enhanceFactoryBean(factoryBean, beanMethod.getReturnType(), beanFactory, beanName);
         }
      }
      //Spring通过通过工厂方法创建时会保存创建对象的工厂方法,所以说第一次调用创建对象方法不会被拦截
      if (isCurrentlyInvokedFactoryMethod(beanMethod)) {
         // The factory is calling the bean method in order to instantiate and register the bean
         // (i.e. via a getBean() call) -> invoke the super implementation of the method to actually
         // create the bean instance.
         if (logger.isInfoEnabled() &&
               BeanFactoryPostProcessor.class.isAssignableFrom(beanMethod.getReturnType())) {
            logger.info(String.format("@Bean method %s.%s is non-static and returns an object " +
                        "assignable to Spring's BeanFactoryPostProcessor interface. This will " +
                        "result in a failure to process annotations such as @Autowired, " +
                        "@Resource and @PostConstruct within the method's declaring " +
                        "@Configuration class. Add the 'static' modifier to this method to avoid " +
                        "these container lifecycle issues; see @Bean javadoc for complete details.",
                  beanMethod.getDeclaringClass().getSimpleName(), beanMethod.getName()));
         }
         //直接使用Spring 工厂方法创建对象
         return cglibMethodProxy.invokeSuper(enhancedConfigInstance, beanMethodArgs);
      }
      //如果不是第一次调用此方法,从容器中直接获取达到单利目的
      return resolveBeanReference(beanMethod, beanMethodArgs, beanFactory, beanName);
   }

   private Object resolveBeanReference(Method beanMethod, Object[] beanMethodArgs,
         ConfigurableBeanFactory beanFactory, String beanName) {

      // The user (i.e. not the factory) is requesting this bean through a call to
      // the bean method, direct or indirect. The bean may have already been marked
      // as 'in creation' in certain autowiring scenarios; if so, temporarily set
      // the in-creation status to false in order to avoid an exception.
      boolean alreadyInCreation = beanFactory.isCurrentlyInCreation(beanName);
      try {
         if (alreadyInCreation) {
            beanFactory.setCurrentlyInCreation(beanName, false);
         }
         boolean useArgs = !ObjectUtils.isEmpty(beanMethodArgs);
         if (useArgs && beanFactory.isSingleton(beanName)) {
            // Stubbed null arguments just for reference purposes,
            // expecting them to be autowired for regular singleton references?
            // A safe assumption since @Bean singleton arguments cannot be optional...
            for (Object arg : beanMethodArgs) {
               if (arg == null) {
                  useArgs = false;
                  break;
               }
            }
         }
         Object beanInstance = (useArgs ? beanFactory.getBean(beanName, beanMethodArgs) :
               beanFactory.getBean(beanName));
         if (!ClassUtils.isAssignableValue(beanMethod.getReturnType(), beanInstance)) {
            // Detect package-protected NullBean instance through equals(null) check
            if (beanInstance.equals(null)) {
               if (logger.isDebugEnabled()) {
                  logger.debug(String.format("@Bean method %s.%s called as bean reference " +
                        "for type [%s] returned null bean; resolving to null value.",
                        beanMethod.getDeclaringClass().getSimpleName(), beanMethod.getName(),
                        beanMethod.getReturnType().getName()));
               }
               beanInstance = null;
            }
            else {
               String msg = String.format("@Bean method %s.%s called as bean reference " +
                     "for type [%s] but overridden by non-compatible bean instance of type [%s].",
                     beanMethod.getDeclaringClass().getSimpleName(), beanMethod.getName(),
                     beanMethod.getReturnType().getName(), beanInstance.getClass().getName());
               try {
                  BeanDefinition beanDefinition = beanFactory.getMergedBeanDefinition(beanName);
                  msg += " Overriding bean of same name declared in: " + beanDefinition.getResourceDescription();
               }
               catch (NoSuchBeanDefinitionException ex) {
                  // Ignore - simply no detailed message then.
               }
               throw new IllegalStateException(msg);
            }
         }
         Method currentlyInvoked = SimpleInstantiationStrategy.getCurrentlyInvokedFactoryMethod();
         if (currentlyInvoked != null) {
            String outerBeanName = BeanAnnotationHelper.determineBeanNameFor(currentlyInvoked);
            beanFactory.registerDependentBean(beanName, outerBeanName);
         }
         return beanInstance;
      }
      finally {
         if (alreadyInCreation) {
            beanFactory.setCurrentlyInCreation(beanName, true);
         }
      }
   }

   @Override
   public boolean isMatch(Method candidateMethod) {
      return (candidateMethod.getDeclaringClass() != Object.class &&
            !BeanFactoryAwareMethodInterceptor.isSetBeanFactory(candidateMethod) &&
            BeanAnnotationHelper.isBeanAnnotated(candidateMethod));
   }