• 3. Spring源码篇之ComponentScan


    简介

    前面介绍了scanner可以扫描某个包路径下的所有bean,我们最常用的也是通过ComponentScan指定包路径去扫描,在SpringBoot中也是如此,本文将介绍spring扫描的逻辑

    BeanDefinitionRegistryPostProcessor

    知道了ComponentScan的作用,那么spring什么时候开始解析ComponentScan去扫描bean呢

    这个时候就要知道spring的其中一个生命周期 BeanDefinitionRegistryPostProcessor

    public interface BeanDefinitionRegistryPostProcessor extends BeanFactoryPostProcessor {
    
    	void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException;
    }
    
    • 1
    • 2
    • 3
    • 4

    该生命周期可以说是最早的一个,还在BeanFactoryPostProcessor#postProcessBeanFactory之前执行

    从接口提供的方法就很明确,可以自己去注册一些bean

    那么在该接口实现类里面就可以将最开始注册的AppConfig类拿出来,确定有ComponentScan注解,就可以拿到路径去扫描,最终注册bean

    ConfigurationClassPostProcessor

    ConfigurationClassPostProcessor 实现了 BeanDefinitionRegistryPostProcessor

    在spring中通过该类进行配置类的解析,并且注册bean,只不过在spring中,标名是一个配置类的注解多种多样 ComponentScan 也只是其中一个

    本文主要讲 ComponentScan 其它配置类后面讲

    注册

    源码链路

    1. AnnotationConfigApplicationContext(Class… componentClasses) # 进入this()

    2. AnnotationConfigApplicationContext()

    3. AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry)

    4. AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry, Environment environment)

    5. AnnotationConfigUtils#registerAnnotationConfigProcessors(BeanDefinitionRegistry registry)

    6. AnnotationConfigUtils#registerAnnotationConfigProcessors(BeanDefinitionRegistry registry, @Nullable Object source)

    可以看到这么一行 注册ConfigurationClassPostProcessor

    if (!registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)) {
        RootBeanDefinition def = new RootBeanDefinition(ConfigurationClassPostProcessor.class);
        def.setSource(source);
        beanDefs.add(registerPostProcessor(registry, def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME));
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    获取注册的ConfigurationClassPostProcessor

    进入refresh方案,spring最重要的一个方法,整个生命周期都在这

    1. AnnotationConfigApplicationContext(Class… componentClasses) # 进入this()
    2. AbstractApplicationContext#refresh()
    3. AbstractApplicationContext.invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory); 处理
      BeanFactory的后置处理器
    4. PostProcessorRegistrationDelegate#invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory,
      List beanFactoryPostProcessors)

    会看到如下代码

    // 获取BeanDefinitionRegistryPostProcessor,一般来说就只有一个 ConfigurationClassPostProcessor
    String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
    for (String ppName : postProcessorNames) {
        if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
            currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
            processedBeans.add(ppName);
        }
    }
    // 排个序
    sortPostProcessors(currentRegistryProcessors, beanFactory);
    registryProcessors.addAll(currentRegistryProcessors);
    // 执行 BeanDefinitionRegistryPostProcessor的postProcessBeanDefinitionRegistry方法
    invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry, beanFactory.getApplicationStartup());
    currentRegistryProcessors.clear();
    
    // 扫描完之后还有可能生成BeanFactoryPostProcessor
    postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
    for (String ppName : postProcessorNames) {
        // 过滤之前执行过的BeanFactoryPostProcessor
        if (!processedBeans.contains(ppName) && beanFactory.isTypeMatch(ppName, Ordered.class)) {
            currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
            processedBeans.add(ppName);
        }
    }
    sortPostProcessors(currentRegistryProcessors, beanFactory);
    registryProcessors.addAll(currentRegistryProcessors);
    invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry, beanFactory.getApplicationStartup());
    currentRegistryProcessors.clear();
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    以上就是获取 ConfigurationClassPostProcessor 到执行它的 postProcessBeanDefinitionRegistry方法的
    逻辑,通过beanFactory.getBeanNamesForType 获取 BeanDefinitionRegistryPostProcessor

    将获取到的BeanDefinitionRegistryPostProcessor 排个序,通过@Order注解或者@javax.annotation.Priority注解确定排序

    遍历执行postProcessBeanDefinitionRegistry方法

    解析 ComponentScan

    那么在ConfigurationClassPostProcessor#postProcessBeanDefinitionRegistry又是怎么解析ComponentScan注册bean呢

    1. ConfigurationClassPostProcessor#postProcessBeanDefinitionRegistry
    2. ConfigurationClassPostProcessor#processConfigBeanDefinitions(BeanDefinitionRegistry registry)
      在这里会有一个检查,判断是不是配置类 ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef,
      this.metadataReaderFactory)
      那么什么是配置类呢,
    public static boolean checkConfigurationClassCandidate(BeanDefinition beanDef, MetadataReaderFactory metadataReaderFactory) {
         // getFactoryMethodName表示是@Bean方式注入的bean,这种不作为配置类
         String className = beanDef.getBeanClassName();
    
         // 注解信息,通过MetadataReader获取(ASM技术) 并没有加载类
         AnnotationMetadata metadata;
    
         // 如果AnnotatedBeanDefinition,则直接取AnnotationMetadata
         if (beanDef instanceof AnnotatedBeanDefinition && className.equals(((AnnotatedBeanDefinition) beanDef).getMetadata().getClassName())) {
             metadata = ((AnnotatedBeanDefinition) beanDef).getMetadata();
         }
         // 如果是AbstractBeanDefinition,则解析beanClass得到AnnotationMetadata
         else if (beanDef instanceof AbstractBeanDefinition && ((AbstractBeanDefinition) beanDef).hasBeanClass()) {
             metadata = AnnotationMetadata.introspect(beanClass);
         }
         else {
             // ASM技术,这里其实也是spring提供的一个工具,我们也可以使用,后续文章介绍
             MetadataReader metadataReader = metadataReaderFactory.getMetadataReader(className);
             metadata = metadataReader.getAnnotationMetadata();
         }
    
         Map<String, Object> config = metadata.getAnnotationAttributes(Configuration.class.getName());
    
         // 存在@Configuration,并且proxyBeanMethods不为false,就是配置类 配置类型为Full
         if (config != null && !Boolean.FALSE.equals(config.get("proxyBeanMethods"))) {
             // 设置属性configurationClass,表示是配置类
             beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_FULL);
         }
         // 存在@Configuration,并且proxyBeanMethods为false时,也是配置类配置类型为lite
         // 不存在@Configuration,存在@Component、@ComponentScan、@Import、@ImportResource中的某一个,也是配置类 配置类型为lite
         // 有@Bean标注的方法也是配置类
         else if (config != null || isConfigurationCandidate(metadata)) {
             beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_LITE);
         }
         else {
             return false;
         }
    
         // It's a full or lite configuration candidate... Let's determine the order value, if any.
         Integer order = getOrder(metadata);
         if (order != null) {
             // 配置类也可以排序,使用 Order注解
             beanDef.setAttribute(ORDER_ATTRIBUTE, order);
         }
    
         return true;
     }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    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());
     }
     
    public static boolean isConfigurationCandidate(AnnotationMetadata metadata) {
         // 接口不管
         if (metadata.isInterface()) {
             return false;
         }
    
         // 只要存在@Component、@ComponentScan、@Import、@ImportResource四个中的一个,就是lite配置类
         for (String indicator : candidateIndicators) {
             if (metadata.isAnnotated(indicator)) {
                 return true;
             }
         }
    
         // Finally, let's look for @Bean methods...
         // 只要存在@Bean注解了的方法,就是lite配置类
         return hasBeanMethods(metadata);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    根据上面的代码逻辑分析,拥有@Configuration @Component、@ComponentScan、@Import、@ImportResource
    或者方法有@Bean注解,那么就是一个配置类,继续后面代码分析

    1. parser.parse(candidates); candidates 就是找出的所有配置累会进入 ConfigurationClassParser#parse(AnnotationMetadata
      metadata, String beanName)
    2. ConfigurationClassParser#processConfigurationClass(ConfigurationClass configClass, Predicate filter)
    3. ConfigurationClassParser#doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass,
      Predicate filter)

    其它配置类先不看,那么会看到会看到如下代码

    // 查看是否有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) {
           // 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();
               }
               // 解析出来还有配置类,继续解析
               if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) {
                   parse(bdCand.getBeanClassName(), holder.getBeanName());
               }
           }
       }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    查看该Bean的有没有ComponentScans或者ComponentScan注解,如果有那么使用ComponentScanAnnotationParser解析

    public Set<BeanDefinitionHolder> parse(AnnotationAttributes componentScan, final String declaringClass) {
    
         ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(this.registry,
                 componentScan.getBoolean("useDefaultFilters"), this.environment, this.resourceLoader);
    
         // bean的名字生成器,默认是首字母小写的类名,可以自己定义其它规则,比如类的全限定名
         Class<? extends BeanNameGenerator> generatorClass = componentScan.getClass("nameGenerator");
         boolean useInheritedGenerator = (BeanNameGenerator.class == generatorClass);
         // 默认为AnnotationBeanNameGenerator
         scanner.setBeanNameGenerator(useInheritedGenerator ? this.beanNameGenerator :
                 BeanUtils.instantiateClass(generatorClass));
    
         // 默认就是扫描包下面的class文件
         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) {
             String[] tokenized = StringUtils.tokenizeToStringArray(this.environment.resolvePlaceholders(pkg),
                     ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS);
             Collections.addAll(basePackages, tokenized);
         }
         for (Class<?> clazz : componentScan.getClassArray("basePackageClasses")) {
             basePackages.add(ClassUtils.getPackageName(clazz));
         }
         if (basePackages.isEmpty()) {
             basePackages.add(ClassUtils.getPackageName(declaringClass));
         }
    
         scanner.addExcludeFilter(new AbstractTypeHierarchyTraversingFilter(false, false) {
             @Override
             protected boolean matchClassName(String className) {
                 // 排除掉自己
                 return declaringClass.equals(className);
             }
         });
         // 开始扫描,注册bean
         return scanner.doScan(StringUtils.toStringArray(basePackages));
     }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55

    以上就是如何解析ComponentScan的逻辑,解析完后,开始扫描,进行BeanDefinition注册,注意是BeanDefinition注册,还不是实例化bean

    1. ClassPathBeanDefinitionScanner#doScan
    2. ClassPathBeanDefinitionScanner#registerBeanDefinition
    3. BeanDefinitionReaderUtils#registerBeanDefinition
    4. DefaultListableBeanFactory#registerBeanDefinition

    最终存放在 beanDefinitionMap beanDefinitionNames 记住这两个属性,特别重要

    private final Map beanDefinitionMap = new ConcurrentHashMap<>(256);

    private volatile List beanDefinitionNames = new ArrayList<>(256);

    以上就是通过ComponentScan注解注册Bean的逻辑了,其它配置类以及实例化bean的逻辑后面文章在介绍


    欢迎关注,学习不迷路!

  • 相关阅读:
    Python武器库开发-flask篇之Get与Post(二十五)
    线性阈值(Linear Threshold)模型的原理及代码实现
    VMWare里Centos系统下使用Bonding技术实现两块网卡绑定
    初识NK-RTU980开发板
    Rust编程中的线程间通信
    国际经济学名词解释
    二、链表(linked-list)
    Java多线程从基本概念到精通大神,大佬给我们铺平学习之路
    规则引擎深度对比,LiteFlow vs Drools!
    SpringCloud之入门
  • 原文地址:https://blog.csdn.net/weixin_44412085/article/details/134455710