protected void processConfigurationClass(ConfigurationClass configClass) throws IOException {
    AnnotationMetadata metadata = configClass.getMetadata();
    if (this.environment != null && ProfileHelper.isProfileAnnotationPresent(metadata)) {
      if (!this.environment.acceptsProfiles(ProfileHelper.getCandidateProfiles(metadata))) {
        return;
      }
    }

    while (metadata != null) {
      doProcessConfigurationClass(configClass, metadata);
      String superClassName = metadata.getSuperClassName();
      if (superClassName != null && !Object.class.getName().equals(superClassName)) {
        if (metadata instanceof StandardAnnotationMetadata) {
          Class<?> clazz = ((StandardAnnotationMetadata) metadata).getIntrospectedClass();
          metadata = new StandardAnnotationMetadata(clazz.getSuperclass());
        } else {
          MetadataReader reader = this.metadataReaderFactory.getMetadataReader(superClassName);
          metadata = reader.getAnnotationMetadata();
        }
      } else {
        metadata = null;
      }
    }
    if (this.configurationClasses.contains(configClass) && configClass.getBeanName() != null) {
      // Explicit bean definition found, probably replacing an import.
      // Let's remove the old one and go with the new one.
      this.configurationClasses.remove(configClass);
    }

    this.configurationClasses.add(configClass);
  }
 /** Factory method to obtain a {@link SourceClass} from a {@link ConfigurationClass}. */
 public SourceClass asSourceClass(ConfigurationClass configurationClass) throws IOException {
   AnnotationMetadata metadata = configurationClass.getMetadata();
   if (metadata instanceof StandardAnnotationMetadata) {
     return asSourceClass(((StandardAnnotationMetadata) metadata).getIntrospectedClass());
   }
   return asSourceClass(configurationClass.getMetadata().getClassName());
 }
  /** Register the {@link Configuration} class itself as a bean definition. */
  private void doLoadBeanDefinitionForConfigurationClassIfNecessary(
      ConfigurationClass configClass) {
    if (configClass.getBeanName() != null) {
      // a bean definition already exists for this configuration class -> nothing to do
      return;
    }

    // no bean definition exists yet -> this must be an imported configuration class (@Import).
    BeanDefinition configBeanDef = new GenericBeanDefinition();
    String className = configClass.getMetadata().getClassName();
    configBeanDef.setBeanClassName(className);
    if (checkConfigurationClassCandidate(configBeanDef, this.metadataReaderFactory)) {
      String configBeanName =
          BeanDefinitionReaderUtils.registerWithGeneratedName(configBeanDef, this.registry);
      configClass.setBeanName(configBeanName);
      if (logger.isDebugEnabled()) {
        logger.debug(
            String.format(
                "Registered bean definition for imported @Configuration class %s", configBeanName));
      }
    } else {
      try {
        MetadataReader reader = this.metadataReaderFactory.getMetadataReader(className);
        AnnotationMetadata metadata = reader.getAnnotationMetadata();
        this.problemReporter.error(
            new InvalidConfigurationImportProblem(className, reader.getResource(), metadata));
      } catch (IOException ex) {
        throw new IllegalStateException("Could not create MetadataReader for class " + className);
      }
    }
  }
 public boolean shouldSkip(ConfigurationClass configClass) {
   Boolean skip = this.skipped.get(configClass);
   if (skip == null) {
     if (configClass.isImported()) {
       boolean allSkipped = true;
       for (ConfigurationClass importedBy : configClass.getImportedBy()) {
         if (!shouldSkip(importedBy)) {
           allSkipped = false;
           break;
         }
       }
       if (allSkipped) {
         // The config classes that imported this one were all skipped, therefore we are
         // skipped...
         skip = true;
       }
     }
     if (skip == null) {
       skip =
           conditionEvaluator.shouldSkip(
               configClass.getMetadata(), ConfigurationPhase.REGISTER_BEAN);
     }
     this.skipped.put(configClass, skip);
   }
   return skip;
 }
 private void processImport(
     ConfigurationClass configClass, String[] classesToImport, boolean checkForCircularImports)
     throws IOException {
   if (checkForCircularImports && this.importStack.contains(configClass)) {
     this.problemReporter.error(
         new CircularImportProblem(configClass, this.importStack, configClass.getMetadata()));
   } else {
     this.importStack.push(configClass);
     AnnotationMetadata importingClassMetadata = configClass.getMetadata();
     for (String candidate : classesToImport) {
       MetadataReader reader = this.metadataReaderFactory.getMetadataReader(candidate);
       if (new AssignableTypeFilter(ImportSelector.class).match(reader, metadataReaderFactory)) {
         // the candidate class is an ImportSelector -> delegate to it to determine imports
         try {
           ImportSelector selector =
               BeanUtils.instantiateClass(Class.forName(candidate), ImportSelector.class);
           ImportSelectorContext context =
               new ImportSelectorContext(importingClassMetadata, this.registry);
           processImport(configClass, selector.selectImports(context), false);
         } catch (ClassNotFoundException ex) {
           throw new IllegalStateException(ex);
         }
       } else {
         // the candidate class not an ImportSelector -> process it as a @Configuration class
         this.importStack.registerImport(importingClassMetadata.getClassName(), candidate);
         processConfigurationClass(new ConfigurationClass(reader, null));
       }
     }
     this.importStack.pop();
   }
 }
 /**
  * Read a particular {@link ConfigurationClass}, registering bean definitions for the class
  * itself, all its {@link Bean} methods
  */
 private void loadBeanDefinitionsForConfigurationClass(ConfigurationClass configClass) {
   AnnotationMetadata metadata = configClass.getMetadata();
   processFeatureAnnotations(metadata);
   doLoadBeanDefinitionForConfigurationClassIfNecessary(configClass);
   for (ConfigurationClassMethod beanMethod : configClass.getMethods()) {
     loadBeanDefinitionsForBeanMethod(beanMethod);
   }
   loadBeanDefinitionsFromImportedResources(configClass.getImportedResources());
 }
 public CircularImportProblem(
     ConfigurationClass attemptedImport, Deque<ConfigurationClass> importStack) {
   super(
       String.format(
           "A circular @Import has been detected: "
               + "Illegal attempt by @Configuration class '%s' to import class '%s' as '%s' is "
               + "already present in the current import stack %s",
           importStack.peek().getSimpleName(),
           attemptedImport.getSimpleName(),
           attemptedImport.getSimpleName(),
           importStack),
       new Location(importStack.peek().getResource(), attemptedImport.getMetadata()));
 }
 public ConfigurationClassBeanDefinition(
     RootBeanDefinition original,
     ConfigurationClass configClass,
     MethodMetadata beanMethodMetadata) {
   super(original);
   this.annotationMetadata = configClass.getMetadata();
   this.factoryMethodMetadata = beanMethodMetadata;
 }
  /** Register the {@link Configuration} class itself as a bean definition. */
  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.isDebugEnabled()) {
      logger.debug("Registered bean definition for imported class '" + configBeanName + "'");
    }
  }
  protected void processConfigurationClass(ConfigurationClass configClass) throws IOException {
    if (this.conditionEvaluator.shouldSkip(
        configClass.getMetadata(), ConfigurationPhase.PARSE_CONFIGURATION)) {
      return;
    }

    ConfigurationClass existingClass = this.configurationClasses.get(configClass);
    if (existingClass != null) {
      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.
        this.configurationClasses.remove(configClass);
        for (Iterator<ConfigurationClass> it = this.knownSuperclasses.values().iterator();
            it.hasNext(); ) {
          if (configClass.equals(it.next())) {
            it.remove();
          }
        }
      }
    }

    // Recursively process the configuration class and its superclass hierarchy.
    SourceClass sourceClass = asSourceClass(configClass);
    do {
      sourceClass = doProcessConfigurationClass(configClass, sourceClass);
    } while (sourceClass != null);

    this.configurationClasses.put(configClass, configClass);
  }
  private void processDeferredImportSelectors() {
    List<DeferredImportSelectorHolder> deferredImports = this.deferredImportSelectors;
    this.deferredImportSelectors = null;
    Collections.sort(deferredImports, DEFERRED_IMPORT_COMPARATOR);

    for (DeferredImportSelectorHolder deferredImport : deferredImports) {
      ConfigurationClass configClass = deferredImport.getConfigurationClass();
      try {
        String[] imports =
            deferredImport.getImportSelector().selectImports(configClass.getMetadata());
        processImports(configClass, asSourceClass(configClass), asSourceClasses(imports), false);
      } catch (BeanDefinitionStoreException ex) {
        throw ex;
      } catch (Exception ex) {
        throw new BeanDefinitionStoreException(
            "Failed to process import candidates for configuration class ["
                + configClass.getMetadata().getClassName()
                + "]",
            ex);
      }
    }
  }
 /**
  * Register member (nested) classes that happen to be configuration classes themselves.
  *
  * @param sourceClass the source class to process
  * @throws IOException if there is any problem reading metadata from a member class
  */
 private void processMemberClasses(ConfigurationClass configClass, SourceClass sourceClass)
     throws IOException {
   for (SourceClass memberClass : sourceClass.getMemberClasses()) {
     if (ConfigurationClassUtils.isConfigurationCandidate(memberClass.getMetadata())
         && !memberClass
             .getMetadata()
             .getClassName()
             .equals(configClass.getMetadata().getClassName())) {
       if (this.importStack.contains(configClass)) {
         this.problemReporter.error(new CircularImportProblem(configClass, this.importStack));
       } else {
         this.importStack.push(configClass);
         try {
           processConfigurationClass(memberClass.asConfigClass(configClass));
         } finally {
           this.importStack.pop();
         }
       }
     }
   }
 }
  /**
   * Read a particular {@link ConfigurationClass}, registering bean definitions for the class itself
   * and all of its {@link Bean} methods.
   */
  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.removeImportingClassFor(configClass.getMetadata().getClassName());
      return;
    }

    if (configClass.isImported()) {
      registerBeanDefinitionForImportedConfigurationClass(configClass);
    }
    for (BeanMethod beanMethod : configClass.getBeanMethods()) {
      loadBeanDefinitionsForBeanMethod(beanMethod);
    }
    loadBeanDefinitionsFromImportedResources(configClass.getImportedResources());
    loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars());
  }
 /**
  * Validate each {@link ConfigurationClass} object.
  *
  * @see ConfigurationClass#validate
  */
 public void validate() {
   for (ConfigurationClass configClass : this.configurationClasses) {
     configClass.validate(this.problemReporter);
   }
 }
  protected void doProcessConfigurationClass(
      ConfigurationClass configClass, AnnotationMetadata metadata) throws IOException {

    // recursively process any member (nested) classes first
    for (String memberClassName : metadata.getMemberClassNames()) {
      MetadataReader reader = this.metadataReaderFactory.getMetadataReader(memberClassName);
      AnnotationMetadata memberClassMetadata = reader.getAnnotationMetadata();
      if (isConfigurationCandidate(memberClassMetadata)) {
        processConfigurationClass(new ConfigurationClass(reader, null));
      }
    }

    // process any @PropertySource annotations
    Map<String, Object> propertySourceAttributes =
        metadata.getAnnotationAttributes(
            org.springframework.context.annotation.PropertySource.class.getName());
    if (propertySourceAttributes != null) {
      String name = (String) propertySourceAttributes.get("name");
      String[] locations = (String[]) propertySourceAttributes.get("value");
      ClassLoader classLoader = this.resourceLoader.getClassLoader();
      for (String location : locations) {
        location = this.environment.resolveRequiredPlaceholders(location);
        ResourcePropertySource ps =
            StringUtils.hasText(name)
                ? new ResourcePropertySource(name, location, classLoader)
                : new ResourcePropertySource(location, classLoader);
        this.propertySources.push(ps);
      }
    }

    // process any @ComponentScan annotions
    Map<String, Object> componentScanAttributes =
        metadata.getAnnotationAttributes(ComponentScan.class.getName());
    if (componentScanAttributes != null) {
      // the config class is annotated with @ComponentScan -> perform the scan immediately
      Set<BeanDefinitionHolder> scannedBeanDefinitions =
          this.componentScanParser.parse(componentScanAttributes);

      // check the set of scanned definitions for any further config classes and parse recursively
      // if necessary
      for (BeanDefinitionHolder holder : scannedBeanDefinitions) {
        if (ConfigurationClassUtils.checkConfigurationClassCandidate(
            holder.getBeanDefinition(), metadataReaderFactory)) {
          try {
            this.parse(holder.getBeanDefinition().getBeanClassName(), holder.getBeanName());
          } catch (ConflictingBeanDefinitionException ex) {
            throw new CircularComponentScanException(
                "A conflicting bean definition was detected while processing @ComponentScan annotations. "
                    + "This usually indicates a circle between scanned packages.",
                ex);
          }
        }
      }
    }

    // process any @Import annotations
    List<Map<String, Object>> allImportAttribs =
        AnnotationUtils.findAllAnnotationAttributes(Import.class, metadata.getClassName(), true);
    for (Map<String, Object> importAttribs : allImportAttribs) {
      processImport(configClass, (String[]) importAttribs.get("value"), true);
    }

    // process any @ImportResource annotations
    if (metadata.isAnnotated(ImportResource.class.getName())) {
      String[] resources =
          (String[]) metadata.getAnnotationAttributes(ImportResource.class.getName()).get("value");
      Class<?> readerClass =
          (Class<?>) metadata.getAnnotationAttributes(ImportResource.class.getName()).get("reader");
      if (readerClass == null) {
        throw new IllegalStateException(
            "No reader class associated with imported resources: "
                + StringUtils.arrayToCommaDelimitedString(resources));
      }
      for (String resource : resources) {
        configClass.addImportedResource(resource, readerClass);
      }
    }

    // process individual @Bean methods
    Set<MethodMetadata> beanMethods = metadata.getAnnotatedMethods(Bean.class.getName());
    for (MethodMetadata methodMetadata : beanMethods) {
      configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
    }
  }
  /**
   * Read the given {@link BeanMethod}, registering bean definitions with the BeanDefinitionRegistry
   * based on its contents.
   */
  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;
    }

    // Consider name and any aliases
    AnnotationAttributes bean = AnnotationConfigUtils.attributesFor(metadata, Bean.class);
    List<String> names = new ArrayList<String>(Arrays.asList(bean.getStringArray("name")));
    String beanName = (names.size() > 0 ? 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)) {
      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(RootBeanDefinition.AUTOWIRE_CONSTRUCTOR);
    beanDef.setAttribute(
        RequiredAnnotationBeanPostProcessor.SKIP_REQUIRED_CHECK_ATTRIBUTE, Boolean.TRUE);

    AnnotationConfigUtils.processCommonDefinitionAnnotations(beanDef, metadata);

    Autowire autowire = bean.getEnum("autowire");
    if (autowire.isAutowire()) {
      beanDef.setAutowireMode(autowire.value());
    }

    String initMethodName = bean.getString("initMethod");
    if (StringUtils.hasText(initMethodName)) {
      beanDef.setInitMethodName(initMethodName);
    }

    String destroyMethodName = bean.getString("destroyMethod");
    if (destroyMethodName != null) {
      beanDef.setDestroyMethodName(destroyMethodName);
    }

    // Consider scoping
    ScopedProxyMode proxyMode = ScopedProxyMode.NO;
    // TODO Determine why type is hard coded to org.springframework.context.annotation.Scope,
    // since AnnotationScopeMetadataResolver supports a custom scope annotation type.
    AnnotationAttributes attributes = AnnotationConfigUtils.attributesFor(metadata, Scope.class);
    if (attributes != null) {
      beanDef.setScope(
          attributes.getAliasedString("value", Scope.class, configClass.getResource()));
      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.isDebugEnabled()) {
      logger.debug(
          String.format(
              "Registering bean definition for @Bean method %s.%s()",
              configClass.getMetadata().getClassName(), beanName));
    }

    this.registry.registerBeanDefinition(beanName, beanDefToRegister);
  }
 public ConfigurationClassBeanDefinition(
     ConfigurationClass configClass, MethodMetadata beanMethodMetadata) {
   this.annotationMetadata = configClass.getMetadata();
   this.factoryMethodMetadata = beanMethodMetadata;
   setLenientConstructorResolution(false);
 }
  /**
   * Read a particular {@link ConfigurationClassMethod}, registering bean definitions with the
   * BeanDefinitionRegistry based on its contents.
   */
  private void loadBeanDefinitionsForBeanMethod(ConfigurationClassMethod beanMethod) {
    ConfigurationClass configClass = beanMethod.getConfigurationClass();
    MethodMetadata metadata = beanMethod.getMetadata();

    RootBeanDefinition beanDef = new ConfigurationClassBeanDefinition(configClass);
    beanDef.setResource(configClass.getResource());
    beanDef.setSource(this.sourceExtractor.extractSource(metadata, configClass.getResource()));
    beanDef.setFactoryBeanName(configClass.getBeanName());
    beanDef.setUniqueFactoryMethodName(metadata.getMethodName());
    beanDef.setAutowireMode(RootBeanDefinition.AUTOWIRE_CONSTRUCTOR);
    beanDef.setAttribute(
        RequiredAnnotationBeanPostProcessor.SKIP_REQUIRED_CHECK_ATTRIBUTE, Boolean.TRUE);

    // consider name and any aliases
    Map<String, Object> beanAttributes = metadata.getAnnotationAttributes(Bean.class.getName());
    List<String> names =
        new ArrayList<String>(Arrays.asList((String[]) beanAttributes.get("name")));
    String beanName =
        (names.size() > 0 ? names.remove(0) : beanMethod.getMetadata().getMethodName());
    for (String alias : names) {
      this.registry.registerAlias(beanName, alias);
    }

    // has this already been overridden (e.g. via XML)?
    if (this.registry.containsBeanDefinition(beanName)) {
      BeanDefinition existingBeanDef = registry.getBeanDefinition(beanName);
      // is the existing bean definition one that was created from a configuration class?
      if (!(existingBeanDef instanceof ConfigurationClassBeanDefinition)) {
        // no -> then it's an external override, probably XML
        // overriding is legal, return immediately
        if (logger.isDebugEnabled()) {
          logger.debug(
              String.format(
                  "Skipping loading bean definition for %s: a definition for bean "
                      + "'%s' already exists. This is likely due to an override in XML.",
                  beanMethod, beanName));
        }
        return;
      }
    }

    if (metadata.isAnnotated(Primary.class.getName())) {
      beanDef.setPrimary(true);
    }

    // is this bean to be instantiated lazily?
    if (metadata.isAnnotated(Lazy.class.getName())) {
      beanDef.setLazyInit(
          (Boolean) metadata.getAnnotationAttributes(Lazy.class.getName()).get("value"));
    } else if (configClass.getMetadata().isAnnotated(Lazy.class.getName())) {
      beanDef.setLazyInit(
          (Boolean)
              configClass.getMetadata().getAnnotationAttributes(Lazy.class.getName()).get("value"));
    }

    if (metadata.isAnnotated(DependsOn.class.getName())) {
      String[] dependsOn =
          (String[]) metadata.getAnnotationAttributes(DependsOn.class.getName()).get("value");
      if (dependsOn.length > 0) {
        beanDef.setDependsOn(dependsOn);
      }
    }

    Autowire autowire = (Autowire) beanAttributes.get("autowire");
    if (autowire.isAutowire()) {
      beanDef.setAutowireMode(autowire.value());
    }

    String initMethodName = (String) beanAttributes.get("initMethod");
    if (StringUtils.hasText(initMethodName)) {
      beanDef.setInitMethodName(initMethodName);
    }

    String destroyMethodName = (String) beanAttributes.get("destroyMethod");
    if (StringUtils.hasText(destroyMethodName)) {
      beanDef.setDestroyMethodName(destroyMethodName);
    }

    // consider scoping
    ScopedProxyMode proxyMode = ScopedProxyMode.NO;
    Map<String, Object> scopeAttributes = metadata.getAnnotationAttributes(Scope.class.getName());
    if (scopeAttributes != null) {
      beanDef.setScope((String) scopeAttributes.get("value"));
      proxyMode = (ScopedProxyMode) scopeAttributes.get("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 = proxyDef.getBeanDefinition();
    }

    if (logger.isDebugEnabled()) {
      logger.debug(
          String.format(
              "Registering bean definition for @Bean method %s.%s()",
              configClass.getMetadata().getClassName(), beanName));
    }

    registry.registerBeanDefinition(beanName, beanDefToRegister);
  }
 public ConfigurationClassBeanDefinition(ConfigurationClass configClass) {
   this.annotationMetadata = configClass.getMetadata();
 }
  private void processImports(
      ConfigurationClass configClass,
      SourceClass currentSourceClass,
      Collection<SourceClass> importCandidates,
      boolean checkForCircularImports)
      throws IOException {

    if (importCandidates.isEmpty()) {
      return;
    }

    if (checkForCircularImports && this.importStack.contains(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);
            invokeAwareMethods(selector);
            if (this.deferredImportSelectors != null
                && selector instanceof DeferredImportSelector) {
              this.deferredImportSelectors.add(
                  new DeferredImportSelectorHolder(configClass, (DeferredImportSelector) selector));
            } else {
              String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata());
              Collection<SourceClass> importSourceClasses = asSourceClasses(importClassNames);
              processImports(configClass, currentSourceClass, importSourceClasses, false);
            }
          } 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);
            invokeAwareMethods(registrar);
            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 (Exception ex) {
        throw new BeanDefinitionStoreException(
            "Failed to process import candidates for configuration class ["
                + configClass.getMetadata().getClassName()
                + "]",
            ex);
      } finally {
        this.importStack.pop();
      }
    }
  }
  /**
   * Apply processing and build a complete {@link ConfigurationClass} by reading the annotations,
   * members and methods from the source class. This method can be called multiple times as relevant
   * sources are discovered.
   *
   * @param configClass the configuration class being build
   * @param sourceClass a source class
   * @return the superclass, or {@code null} if none found or previously processed
   */
  protected final SourceClass doProcessConfigurationClass(
      ConfigurationClass configClass, SourceClass sourceClass) throws IOException {
    // 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) {
        processPropertySource(propertySource);
      } else {
        logger.warn(
            "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 necessary
        for (BeanDefinitionHolder holder : scannedBeanDefinitions) {
          if (ConfigurationClassUtils.checkConfigurationClassCandidate(
              holder.getBeanDefinition(), this.metadataReaderFactory)) {
            parse(holder.getBeanDefinition().getBeanClassName(), holder.getBeanName());
          }
        }
      }
    }

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

    // Process any @ImportResource annotations
    if (sourceClass.getMetadata().isAnnotated(ImportResource.class.getName())) {
      AnnotationAttributes importResource =
          AnnotationConfigUtils.attributesFor(sourceClass.getMetadata(), ImportResource.class);
      String[] resources =
          importResource.getAliasedStringArray("locations", ImportResource.class, sourceClass);
      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 =
        sourceClass.getMetadata().getAnnotatedMethods(Bean.class.getName());
    for (MethodMetadata methodMetadata : beanMethods) {
      configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
    }

    // Process default methods on interfaces
    for (SourceClass ifc : sourceClass.getInterfaces()) {
      beanMethods = ifc.getMetadata().getAnnotatedMethods(Bean.class.getName());
      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));
        }
      }
    }

    // Process superclass, if any
    if (sourceClass.getMetadata().hasSuperClass()) {
      String superclass = sourceClass.getMetadata().getSuperClassName();
      if (!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;
  }