spring5 源码深度解析----- 被面试官给虐懵了,竟然是因为我不懂@Configuration配置类及@Bean的原理

Posted chen_hao

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了spring5 源码深度解析----- 被面试官给虐懵了,竟然是因为我不懂@Configuration配置类及@Bean的原理相关的知识,希望对你有一定的参考价值。

@Configuration注解提供了全新的bean创建方式。最初spring通过xml配置文件初始化bean并完成依赖注入工作。从spring3.0开始,在spring framework模块中提供了这个注解,搭配@Bean等注解,可以完全不依赖xml配置,在运行时完成bean的创建和初始化工作。例如:

public interface IBean {

}

public class AppBean implements IBean{

}

//@Configuration申明了AppConfig是一个配置类
@Configuration 
public class AppConfig {
    //@Bean注解申明了一个bean,bean名称默认为方法名appBean
    @Bean 
    IBean appBean(){
        return new AppBean();
    }
}

默认情况下bean的名称和方法名称相同,你也可以使用name属性来指定,如@Bean(name = "myBean")

@Configuration注解使用

我们先来看看@Configuration 这个注解的定义

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component //@Component元注解
public @interface Configuration {
    String value() default "";
}

我们看到源码里面,@Configuration 标记了@Component元注解,因此可以被@ComponentScan扫描并处理,在Spring容器初始化时Configuration类 会被注册到Bean容器中,最后还会实例化。

使用@Autowired/@Inject

因为@Configuration本身也是一个@Component,因此配置类本身也会被注册到应用上下文,并且也可以使用IOC的@Autowired/@Inject等注解来注入所需bean。我们来修改配置类如下:

@Configuration
public class AppConfig {
    @Autowired
    public Environment env;
    @Bean
    IBean appBean(){
        return new AppBean();
    }
}

使用@CompomentScan

配置类也可以自己添加注解@CompomentScan,来显式扫描需使用组件。

@Configuration 使用@Component 进行原注解,因此@Configuration 类也可以被组件扫描到(特别是使用XML元素)。

@Configuration
@ComponentScan("abc.xxx")
public class AppConfig {
    @Bean
    IBean appBean(){
        return new AppBean();
    }
}

在这里认识几个注解: @Controller, @Service, @Repository, @Component

  • @Controller: 表明一个注解的类是一个"Controller",也就是控制器,可以把它理解为MVC 模式的Controller 这个角色。这个注解是一个特殊的@Component,允许实现类通过类路径的扫描扫描到。它通常与@RequestMapping 注解一起使用。

  • @Service: 表明这个带注解的类是一个"Service",也就是服务层,可以把它理解为MVC 模式中的Service层这个角色,这个注解也是一个特殊的@Component,允许实现类通过类路径的扫描扫描到

  • @Repository: 表明这个注解的类是一个"Repository",团队实现了JavaEE 模式中像是作为"Data Access Object" 可能作为DAO来使用,当与 PersistenceExceptionTranslationPostProcessor 结合使用时,这样注释的类有资格获得Spring转换的目的。这个注解也是@Component 的一个特殊实现,允许实现类能够被自动扫描到

  • @Component: 表明这个注释的类是一个组件,当使用基于注释的配置和类路径扫描时,这些类被视为自动检测的候选者。

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Controller {

    @AliasFor(annotation = Component.class)
    String value() default "";

}

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Service {

    @AliasFor(annotation = Component.class)
    String value() default "";

}

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Repository {

    @AliasFor(annotation = Component.class)
    String value() default "";

}

我们可以看到@Controller, @Service, @Repository这三个注解上都有@Component这个注解

也就是说,上面四个注解标记的类都能够通过@ComponentScan 扫描到,上面四个注解最大的区别就是使用的场景和语义不一样,比如你定义一个Service类想要被Spring进行管理,你应该把它定义为@Service 而不是@Controller因为我们从语义上讲,@Service更像是一个服务的类,而不是一个控制器的类,@Component通常被称作组件,它可以标注任何你没有严格予以说明的类,比如说是一个配置类,它不属于MVC模式的任何一层,这个时候你更习惯于把它定义为 @Component。@Controller,@Service,@Repository 的注解上都有@Component,所以这三个注解都可以用@Component进行替换。

同@Import注解组合使用

新建一个配置类,例如数据库配置类:

@Configuration
public class DatabaseConfig {
    @Bean
    public DataSource dataSource(){
        return new DataSource(){
            ...
        };
    }
}

然后在AppConfig中用@Import来导入配置类

@Configuration
@Import(DatabaseConfig.class)
public class AppConfig {
    @Autowired
    public DataSource dataSource; //注入的bean在DatabaseConfig.class中定义
    @Bean
    IBean appBean(){
        return new AppBean();
    }
}

最后执行:

ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
DatabaseConfig dataSourceConfig = context.getBean(DatabaseConfig.class);

可以看到只注册了AppConfig.class,容器自动会把@Import指向的配置类初始化。

同@Profile注解组合使用

在配置类中可以申明@Profile注解,仅当满足profile条件时,才会处理配置类,也可以将@Profile注解加载配置类中的每一个@Bean来实现更细粒度的条件控制。

@Configuration
@Profile("develop")
public class DatabaseConfig {
    @Bean
    public DataSource dataSource(){
        return new DataSource(){...};
    }
}

嵌套使用@Configuration

在配置类中可以创建静态内部类,并添加@Configuration注解,这样上下文只需要注册最外面的配置类,内部的配置类会自动被加载。这样做省略了@Import,因为本身就在配置类内部,无需再特别指定了。

@Configuration
public class AppConfig {
    @Autowired
    public DataSource dataSource; //注入的bean在内部定义

    @Configuration
    public static class DatabaseConfig{
        @Bean
        DataSource dataSource(){
            return new DataSource() {...};
        }
    }
    
    @Bean
    IBean appBean(){
        return new AppBean();
    }
}

注意:任何嵌套的@Configuration 都必须是static 的。

@Lazy初始化

默认情况下,配置类中的Bean都随着应用上下文被初始化,可以在配置类中添加@Lazy注解来延迟初始化,当然也可以在每个@Bean注解上添加,来实现更细粒度的控制。

@Configuration
@Lazy//延时加载
public class AppConfig {
    @Bean
    IBean appBean(){
        return new AppBean();
    }
}

配置类约束

  • 配置类必须为显式申明的类,而不能通过工厂类方法返回实例。允许运行时类增强。
  • 配置类不允许标记final。
  • 配置类必须全局可见(不允许定义在方法本地内部类中)
  • 嵌套配置类必须申明为static 内部类
  • @Bean方法不可以再创建新的配置类(所有实例都当做bean处理,不解析相关配置注解)

@Configuration源码

ApplicationContext的refresh方法

在我之前的一篇文章spring5 源码深度解析-----ApplicationContext容器refresh过程中写过,Spring容器启动时,即ApplicationContext接口实现类的对象实例执行refresh方法时,在Bean初始化完成之前,有一个扩展点,用来操作BeanFactory,来扩展对应的功能,比喻往BeanFactory中注册BeanDefintion,我们回顾一下ApplicationContext的refresh函数:

 1 public void refresh() throws BeansException, IllegalStateException {
 2     synchronized (this.startupShutdownMonitor) {
 3         //准备刷新的上下文 环境  
 4         prepareRefresh();
 5         //初始化BeanFactory,并进行XML文件读取  
 6         ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
 7         //对beanFactory进行各种功能填充  
 8         prepareBeanFactory(beanFactory);
 9         try {
10             postProcessBeanFactory(beanFactory);
11             //激活各种beanFactory处理器  
12             invokeBeanFactoryPostProcessors(beanFactory);
13             //注册拦截Bean创建的Bean处理器,这里只是注册,真正的调用实在getBean时候 
14             registerBeanPostProcessors(beanFactory);
15             //为上下文初始化Message源,即不同语言的消息体,国际化处理  
16             initMessageSource();
17             //初始化应用消息广播器,并放入“applicationEventMulticaster”bean中  
18             initApplicationEventMulticaster();
19             //留给子类来初始化其它的Bean  
20             onRefresh();
21             //在所有注册的bean中查找Listener bean,注册到消息广播器中  
22             registerListeners();
23             //初始化剩下的单实例(非惰性的)  
24             finishBeanFactoryInitialization(beanFactory);
25             //完成刷新过程,通知生命周期处理器lifecycleProcessor刷新过程,同时发出ContextRefreshEvent通知别人  
26             finishRefresh();
27         }
28         catch (BeansException ex) {
29             if (logger.isWarnEnabled()) {
30                 logger.warn("Exception encountered during context initialization - " +
31                         "cancelling refresh attempt: " + ex);
32             }
33             destroyBeans();
34             cancelRefresh(ex);
35             throw ex;
36         }
37         finally {
38             resetCommonCaches();
39         }
40     }
41 }

看到第12行,在初始化BeanFactory后,会激活各种beanFactory处理器,我们来看看invokeBeanFactoryPostProcessors方法

 1 public static void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {
 2 
 3     // Invoke BeanDefinitionRegistryPostProcessors first, if any.
 4     // 1、首先调用BeanDefinitionRegistryPostProcessors
 5     Set<String> processedBeans = new HashSet<>();
 6 
 7     // beanFactory是BeanDefinitionRegistry类型
 8     if (beanFactory instanceof BeanDefinitionRegistry) {
 9         BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
10         // 定义BeanFactoryPostProcessor
11         List<BeanFactoryPostProcessor> regularPostProcessors = new ArrayList<>();
12         // 定义BeanDefinitionRegistryPostProcessor集合
13         List<BeanDefinitionRegistryPostProcessor> registryProcessors = new ArrayList<>();
14 
15         // 循环手动注册的beanFactoryPostProcessors
16         for (BeanFactoryPostProcessor postProcessor : beanFactoryPostProcessors) {
17             // 如果是BeanDefinitionRegistryPostProcessor的实例话,则调用其postProcessBeanDefinitionRegistry方法,对bean进行注册操作
18             if (postProcessor instanceof BeanDefinitionRegistryPostProcessor) {
19                 // 如果是BeanDefinitionRegistryPostProcessor类型,则直接调用其postProcessBeanDefinitionRegistry
20                 BeanDefinitionRegistryPostProcessor registryProcessor = (BeanDefinitionRegistryPostProcessor) postProcessor;
21                 registryProcessor.postProcessBeanDefinitionRegistry(registry);
22                 registryProcessors.add(registryProcessor);
23             }
24             // 否则则将其当做普通的BeanFactoryPostProcessor处理,直接加入regularPostProcessors集合,以备后续处理
25             else {
26                 regularPostProcessors.add(postProcessor);
27             }
28         }
29         //略....
30     }
31 
32     // 2、如果不是BeanDefinitionRegistry的实例,那么直接调用其回调函数即可-->postProcessBeanFactory
33     else {
34         // Invoke factory processors registered with the context instance.
35         invokeBeanFactoryPostProcessors(beanFactoryPostProcessors, beanFactory);
36     }
37     //略....
38 }

我们看看第21行,看看其实现类,如下截图,发现其中有一个ConfigurationClassPostProcessor,这个类就是本章的重点

ConfigurationClassPostProcessor这个BeanFactoryPostProcessor,来开启整个@Configuration注解的系列类的加载的,即开启基于@Configuration的类配置代替beans标签的容器配置的相关bean的加载。

ConfigurationClassPostProcessor

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);
   }
   this.registriesPostProcessed.add(registryId);
   //解析Java类配置bean
   processConfigBeanDefinitions(registry);
}

processConfigBeanDefinitions(registry)处理逻辑:

public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
   List<BeanDefinitionHolder> configCandidates = new ArrayList<>();
  //所有已经注册的bean 
   String[] candidateNames = registry.getBeanDefinitionNames();
   //遍历bean定义信息
   for (String beanName : candidateNames) {
      BeanDefinition beanDef = registry.getBeanDefinition(beanName);
      if (ConfigurationClassUtils.isFullConfigurationClass(beanDef) ||
            ConfigurationClassUtils.isLiteConfigurationClass(beanDef)) {
         if (logger.isDebugEnabled()) {
            logger.debug("Bean definition has already been processed as a configuration class: " + beanDef);
         }
      }
    //1.如果当前的bean是Javabean配置类(含有@Configuration注解的类),则加入到集合configCandidates中
      else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {
         configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));
      }
   }

   // Return immediately if no @Configuration classes were found
  // 没有@Configuration注解的类,直接退出
   if (configCandidates.isEmpty()) {
      return;
   }

   // 多个Java配置类,按@Ordered注解排序
   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) {
         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
  //初始化一个ConfigurationClassParser解析器,可以解析@Congiguration配置类
   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());
   do {
   //2.解析Java配置类
      parser.parse(candidates);
   //主要校验配置类不能使用final修饰符(CGLIB代理是生成一个子类,因此原先的类不能使用final修饰)
      parser.validate();

      //排除已处理过的配置类
      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());
      }
    //3.加载bean定义信息,主要实现将@bean @Configuration @Import @ImportResource @ImportRegistrar注册为bean
      this.reader.loadBeanDefinitions(configClasses);
      alreadyParsed.addAll(configClasses);
      //清空已处理的配置类
      candidates.clear();
   //再次获取容器中bean定义数量  如果大于 之前获取的bean定义数量,则说明有新的bean注册到容器中,需要再次解析
      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());
         }
         for (String candidateName : newCandidateNames) {
            if (!oldCandidateNames.contains(candidateName)) {
               BeanDefinition bd = registry.getBeanDefinition(candidateName);
        //新注册的bean如果也是@Configuration配置类,则添加到数据,等待解析
               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)) {
      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();
   }
}

processConfigBeanDefinitions整个方法可以大体划分为三个阶段:

  1. 从容器中获取和Configuration有关系的BeanDefinition
  2. 以该BeanDefinition为起点,进行解析操作,得到解析结果集
  3. 将解析到的结果集加载到容器中,即构造成一个BeanDefinition放到容器中待初始化

1、判断类是否与@Configuration有关

在上面第1步中,有@Configuration注解的会加入到集合当中,这个判断是在ConfigurationClassUtils#checkConfigurationClassCandidate当中实现

public static boolean checkConfigurationClassCandidate(BeanDefinition beanDef, MetadataReaderFactory metadataReaderFactory) {
    String className = beanDef.getBeanClassName();
    if (className == null || beanDef.getFactoryMethodName() != null) {
        return false;
    }
    //获取注解元数据信息
    AnnotationMetadata metadata;
    if (beanDef instanceof AnnotatedBeanDefinition &&
            className.equals(((AnnotatedBeanDefinition) beanDef).getMetadata().getClassName())) {
        metadata = ((AnnotatedBeanDefinition) beanDef).getMetadata();
    }
    else if (beanDef instanceof AbstractBeanDefinition && ((AbstractBeanDefinition) beanDef).hasBeanClass()) {
        Class<?> beanClass = ((AbstractBeanDefinition) beanDef).getBeanClass();
        metadata = new StandardAnnotationMetadata(beanClass, true);
    }
    else {
        try {
            MetadataReader metadataReader = metadataReaderFactory.getMetadataReader(className);
            metadata = metadataReader.getAnnotationMetadata();
        }
        catch (IOException ex) {
            return false;
        }
    }
    // 查找当前注解是否是与@Configuration相关
    // 该方法还会判断该注解上的注解是否有@Configuration,一直往上寻找
    // 因为有的注解为复合注解
    if (isFullConfigurationCandidate(metadata)) {
        beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_FULL);
    }
    // 查找当前注解上是否有ComponentScan、Component、Import、ImportResource注解
    //如果没有则查找Bean注解,同上,一直往上查找
    else if (isLiteConfigurationCandidate(metadata)) {
        beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_LITE);
    }
    else {
        return false;
    }
    return true;
}

我们看看isFullConfigurationCandidate和isLiteConfigurationCandidate

public static boolean isFullConfigurationCandidate(AnnotationMetadata metadata) {
    return metadata.isAnnotated(Configuration.class.getName());
}
public static boolean isLiteConfigurationCandidate(AnnotationMetadata metadata) {
    // Do not consider an interface or an annotation...
    if (metadata.isInterface()) {
        return false;
    }

    // Any of the typical annotations found?
    for (String indicator : candidateIndicators) {
        if (metadata.isAnnotated(indicator)) {
            return true;
        }
    }

    // Finally, let\'s look for @Bean methods...
    try {
        return metadata.hasAnnotatedMethods(Bean.class.getName());
    }
    catch (Throwable ex) {
        if (logger.isDebugEnabled()) {
            logger.debug("Failed to introspect @Bean methods on class [" + metadata.getClassName() + "]: " + ex);
        }
        return false;
    }
}

private static final Set<String> candidateIndicators = new HashSet<>(8);

static {
    candidateIndicators.add(Component.class.getName());
    candidateIndicators.add(ComponentScan.class.getName());
    candidateIndicators.add(Import.class.getName());
    candidateIndicators.add(ImportResource.class.getName());
}

2、解析Java配置类parser.parse(candidates)

parser.parse(candidates)方法最终调用processConfigurationClass方法来处理@Configuration配置类,ConfigurationClassParser. processConfigurationClass()方法实现代码如下:

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);
         this.knownSuperclasses.values().removeIf(configClass::equals);
      }
   }

   // 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);
}

doProcessConfigurationClass方法主要实现从配置类中解析所有bean,包括处理内部类,父类以及各种注解

ConfigurationClassParser. doProcessConfigurationClass()解析配置类逻辑如下:

protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass)
      throws IOException {

   //递归处理任何成员(嵌套)类
   processMemberClasses(configClass, sourceClass);

   // 处理@PropertySource注解
   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");
      }
   }

   // 处理@ComponentScan 
   //获取@ComponentScan注解信息
   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) {

         // 按@CmponentScan注解扫描bean
         Set<BeanDefinitionHolder> scannedBeanDefinitions =
               this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());
         // 遍历扫描出的bean定义是否是配置类bean
         for (BeanDefinitionHolder holder : scannedBeanDefinitions) {
            BeanDefinition bdCand = holder.getBeanDefinition().getOriginatingBeanDefinition();
            if (bdCand == null) {
               bdCand = holder.getBeanDefinition();
            }
            //若果扫描出的bean定义是配置类(含有@COnfiguration),则继续调用parse方法,内部再次调用doProcessConfigurationClas(),递归解析
            if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) {
               parse(bdCand.getBeanClassName(), holder.getBeanName());
            }
         }
      }
   }

   //处理@Import注解
   processImports(configClass, sourceClass, getImports(sourceClass), true);

   //处理@ImportResource注解
   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);
      }
   }

   以上是关于spring5 源码深度解析----- 被面试官给虐懵了,竟然是因为我不懂@Configuration配置类及@Bean的原理的主要内容,如果未能解决你的问题,请参考以下文章

原创 | 我被面试官给虐懵了,竟然是因为我不懂Spring中的@Configuration

spring5 源码深度解析-----ApplicationContext容器refresh过程

深度解析Spring源码编译Spring源码(spring5.2.x版本)

被面试官吊打系列之JUC之 可重入读写锁ReentrantReadWriteLock 之 源码详尽分析

spring5 源码深度解析-----Spring的整体架构和环境搭建

spring5 源码深度解析----- Spring事务 是怎么通过AOP实现的?(100%理解Spring事务)