Spring 基于ClassPathXmlApplicationContext的初始化流程04-<context:component-scan>包扫描过程

        在上一小节中,记录了Spring自定义标签的加载过程,Spring自定义标签处理的Handler从spring-context包下的/META-INF/spring.handlers文件中都可以找到,简单来说就是Spring会为每一个标签维护一个Parser类,在各自的Parser类中实现自己的parse()方法。在本小节中将记录Spring通过<context:component-scan>标签进行包扫描的整个过程。本小节的入口是ComponentScanBeanDefinitionParser这个类。

        这个类的加载过程在上一节中已经详细说明,不再赘述,直接进入这个类的parse()方法。

    @Nullable
    public BeanDefinition parse(Element element, ParserContext parserContext) {
        //这一步不用多说,从标签中获取base-package属性,即包扫描的基础路径
        String basePackage = element.getAttribute("base-package");
        //basePackage可能是以占位符${}的形式,这一步是对占位符进行解析并替换
        basePackage = parserContext.getReaderContext().getEnvironment().resolvePlaceholders(basePackage);
        //将逗号分隔的字符串转化成一个数组,说明basePackage可以配置多个路径,中间用逗号分隔
        String[] basePackages = StringUtils.tokenizeToStringArray(basePackage, ",; \t\n");
        ClassPathBeanDefinitionScanner scanner = this.configureScanner(parserContext, element);
        Set<BeanDefinitionHolder> beanDefinitions = scanner.doScan(basePackages);
        this.registerComponents(parserContext.getReaderContext(), beanDefinitions, element);
        return null;
    }

        第一步,获取标签中的base-package属性,如果属性值是占位符${}的形式,则对占位符进行解析并替换,如果不是占位符则直接处理原字符串。先简单记录basePackage = parserContext.getReaderContext().getEnvironment().resolvePlaceholders(basePackage)方法,从Environment对象中获取相应的key对应的值,进行填充。在这一步中,Spring的Environment对象中只有环境变量相关参数。

        第二步,如果basePackage字符串中是使用逗号分隔的多个路径,则可以转化成一个数组。

        第三步,调用ClassPathBeanDefinitionScanner scanner = this.configureScanner(parserContext, element),创建scanner对象,通过这个对象是进行后面包扫描操作的核心对象,记录下这个对象的生成过程。

protected ClassPathBeanDefinitionScanner configureScanner(ParserContext parserContext, Element element) {
        boolean useDefaultFilters = true;
        //标签中默认会有这个属性,默认值为true
        if (element.hasAttribute("use-default-filters")) {
            useDefaultFilters = Boolean.parseBoolean(element.getAttribute("use-default-filters"));
        }

        //创建scanner对象,需要进入createScanner()方法具体看下它的创建过程
        ClassPathBeanDefinitionScanner scanner = this.createScanner(parserContext.getReaderContext(), useDefaultFilters);
        scanner.setBeanDefinitionDefaults(parserContext.getDelegate().getBeanDefinitionDefaults());
        scanner.setAutowireCandidatePatterns(parserContext.getDelegate().getAutowireCandidatePatterns());
        if (element.hasAttribute("resource-pattern")) {
            scanner.setResourcePattern(element.getAttribute("resource-pattern"));
        }

        try {
            this.parseBeanNameGenerator(element, scanner);
        } catch (Exception var7) {
            parserContext.getReaderContext().error(var7.getMessage(), parserContext.extractSource(element), var7.getCause());
        }

        try {
            this.parseScope(element, scanner);
        } catch (Exception var6) {
            parserContext.getReaderContext().error(var6.getMessage(), parserContext.extractSource(element), var6.getCause());
        }

        this.parseTypeFilters(element, scanner, parserContext);
        return scanner;
    }

        标签中默认有一个use-default-filters属性,且默认值为true。这个属性的含义是如果不在标签中配置其他属性,标签会扫描满足它默认条件的类,我们继续跟下去,看下这个属性值是在哪用到的。

        方法中接下来调用this.createScanner(parserContext.getReaderContext(), useDefaultFilters)方法,同时把useDefaultFilters=true的属性传进去,进入这个方法:

ComponentScanBeanDefinitionParser

protected ClassPathBeanDefinitionScanner createScanner(XmlReaderContext readerContext, boolean useDefaultFilters) {
//这个方法中又创建了一个ClassPathBeanDefinitionScanner对象
        return new ClassPathBeanDefinitionScanner(readerContext.getRegistry(), useDefaultFilters, readerContext.getEnvironment(), readerContext.getResourceLoader());
    }

/**
*  这个类就是上面的方法中new出来的  
*/
public ClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry, boolean useDefaultFilters, Environment environment, @Nullable ResourceLoader resourceLoader) {
        this.beanDefinitionDefaults = new BeanDefinitionDefaults();
        this.beanNameGenerator = AnnotationBeanNameGenerator.INSTANCE;
        this.scopeMetadataResolver = new AnnotationScopeMetadataResolver();
        this.includeAnnotationConfig = true;
        Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
        this.registry = registry;
        //注意看这里,刚才获取的默认属性值在这里用到了,因为这个属性为true,所以会进入this.registerDefaultFilters()这个方法
        if (useDefaultFilters) {
            this.registerDefaultFilters();
        }

        this.setEnvironment(environment);
        this.setResourceLoader(resourceLoader);
    }

        刚才获取到的属性默认值是在ClassPathBeanDefinitionScanner类的构造方法中用到了,程序会进入到this.registerDefaultFilters(),这个方法的作用是收集默认扫描Filters,再进到这个方法里

protected void registerDefaultFilters() {
        //进到这个方法中,便豁然开朗,component-scan标签默认扫描的就是basePackage包路径下所有加了@Component注解的类
        this.includeFilters.add(new AnnotationTypeFilter(Component.class));
        ClassLoader cl = ClassPathScanningCandidateComponentProvider.class.getClassLoader();

        try {
            this.includeFilters.add(new AnnotationTypeFilter(ClassUtils.forName("javax.annotation.ManagedBean", cl), false));
            this.logger.trace("JSR-250 'javax.annotation.ManagedBean' found and supported for component scanning");
        } catch (ClassNotFoundException var4) {
            ;
        }

        try {
            this.includeFilters.add(new AnnotationTypeFilter(ClassUtils.forName("javax.inject.Named", cl), false));
            this.logger.trace("JSR-330 'javax.inject.Named' annotation found and supported for component scanning");
        } catch (ClassNotFoundException var3) {
            ;
        }

    }

        由此可知,默认情况下<context:component-scan>标签只会把@Component注解加入到TypeFilter中,这说明在后面的扫描过程中,只会将带@Compnent注解的类作为候选,变成BeanDefinition。

        第四步,scanner对象已创建完毕,类型是ClassPathBeanDefinitionScanner,内部包含了includeFilters和excludeFilters两个集合,执行scanner.doScan()方法进行扫描,扫描的目的是将满足条件的类变成BeanDefinition,代码如下:

Set<BeanDefinitionHolder> beanDefinitions = scanner.doScan(basePackages);

protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
        Assert.notEmpty(basePackages, "At least one base package must be specified");
        Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet();
        String[] var3 = basePackages;
        int var4 = basePackages.length;

        for(int var5 = 0; var5 < var4; ++var5) {
            String basePackage = var3[var5];
            //首先是找到basePackage下的所有候选类
            Set<BeanDefinition> candidates = this.findCandidateComponents(basePackage);
            Iterator var8 = candidates.iterator();

            while(var8.hasNext()) {
//遍历每一个候选类生成的BeanDefinition对象,将里面还没有填充的属性全部填充完
                BeanDefinition candidate = (BeanDefinition)var8.next();
                ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);
                candidate.setScope(scopeMetadata.getScopeName());
                String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);
                if (candidate instanceof AbstractBeanDefinition) {
                    this.postProcessBeanDefinition((AbstractBeanDefinition)candidate, beanName);
                }

                if (candidate instanceof AnnotatedBeanDefinition) {
                    AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition)candidate);
                }

                if (this.checkCandidate(beanName, candidate)) {
                    BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
                    definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
                    beanDefinitions.add(definitionHolder);
//最终调用registerBeanDefinition()方法将bd对象注册到BeanDefinitionRegistry对象中,完成bd的注册
                    this.registerBeanDefinition(definitionHolder, this.registry);
                }
            }
        }

        return beanDefinitions;
    }

        先来看这一部分:Set<BeanDefinition> candidates = this.findCandidateComponents(basePackage);找到所有候选的类,并把它们变成BeanDefinition,具体实现如下:

    public Set<BeanDefinition> findCandidateComponents(String basePackage) {
    //this.indexSupportsIncludeFilters()用来判断是否有includeFilters,根据我们之前的分析,这里includeFilter是有的,且里面的元素就是@Component注解
    //因此,这里是false,程序执行后面的逻辑,即this.scanCandidateComponents(basePackage);
        return this.componentsIndex != null && this.indexSupportsIncludeFilters() ? this.addCandidateComponentsFromIndex(this.componentsIndex, basePackage) : this.scanCandidateComponents(basePackage);
    }

/**
*这就是扫描候选类的逻辑
*/
private Set<BeanDefinition> scanCandidateComponents(String basePackage) {
        LinkedHashSet candidates = new LinkedHashSet();

        try {
            String packageSearchPath = "classpath*:" + this.resolveBasePackage(basePackage) + '/' + this.resourcePattern;
//扫描basePackage及子包下的所有.class文件,转成Resouce对象
            Resource[] resources = this.getResourcePatternResolver().getResources(packageSearchPath);
            boolean traceEnabled = this.logger.isTraceEnabled();
            boolean debugEnabled = this.logger.isDebugEnabled();
            Resource[] var7 = resources;
            int var8 = resources.length;

            for(int var9 = 0; var9 < var8; ++var9) {
                Resource resource = var7[var9];
                if (traceEnabled) {
                    this.logger.trace("Scanning " + resource);
                }

                if (resource.isReadable()) {
                    try {
//这里比较重要,这里获取的是类的MetadataReader对象,目的是获取到Metadata对象,该对象里包含了这个类所有的类及注解信息,是非常重要的,后面我们也会多次见到它。
                        MetadataReader metadataReader = this.getMetadataReaderFactory().getMetadataReader(resource);
//这一步是判断该类的Metadata对象中是否包含@Component注解,能够满足成为候选对象的条件。
                        if (this.isCandidateComponent(metadataReader)) {
                            ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);
                            sbd.setResource(resource);
                            sbd.setSource(resource);
                            if (this.isCandidateComponent((AnnotatedBeanDefinition)sbd)) {
                                if (debugEnabled) {
                                    this.logger.debug("Identified candidate component class: " + resource);
                                }

                                candidates.add(sbd);
                            } else if (debugEnabled) {
                                this.logger.debug("Ignored because not a concrete top-level class: " + resource);
                            }
                        } else if (traceEnabled) {
                            this.logger.trace("Ignored because not matching any filter: " + resource);
                        }
                    } catch (Throwable var13) {
                        throw new BeanDefinitionStoreException("Failed to read candidate component class: " + resource, var13);
                    }
                } else if (traceEnabled) {
                    this.logger.trace("Ignored because not readable: " + resource);
                }
            }

            return candidates;
        } catch (IOException var14) {
            throw new BeanDefinitionStoreException("I/O failure during classpath scanning", var14);
        }
    }

        在上面的步骤中,首先通过 MetadataReader metadataReader = this.getMetadataReaderFactory().getMetadataReader(resource);通过Resouece获取MetadataReader对象,这个对象中包含了类的元信息及注解信息,下一步又调用了this.isCandidateComponent(metadataReader)方法来判断该类是否为候选类,它的核心原理就是判断该类上是否有注解是包含在includeFilters集合中的,从上面我们已知Spring默认将@Component注解加入到了includeFilter中,因此如果类上有@Component注解,该方法即返回true,否则返回false。当返回true,执行ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);创建一个ScannedGenericBeanDefinition对象,并加入到候选的bd集合中。注意:此时的sbd对象只是通过MetadataReader对象创建出来,里面还有很多属性还没填充。

         第五步,将上面生成的bd还没有填充的属性如Lazy、Primary、DependOn、Description等填充完整,然后调用this.registerBeanDefinition(definitionHolder, this.registry);将bd对象注册到BeanDefinitionRegistry中,完成注册。在BeanDefinitionRegistry对象中维护了beanDefinitionNames和beanDefinitionMap两个集合,注册的核心就是将bd对象分别填充到这两个集合中,在后面的Bean实例化过程中会遍历这两个集合,依次将其实例化。

         第六步,执行到此,文中的入口parse()方法,就只剩下最后一步,this.registerComponents(parserContext.getReaderContext(), beanDefinitions, element);在这个方法里有一处方法调用需要记录一下:Set<BeanDefinitionHolder> processorDefinitions = AnnotationConfigUtils.registerAnnotationConfigProcessors(readerContext.getRegistry(), source);实现如下: 

public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors(BeanDefinitionRegistry registry, @Nullable Object source) {
        DefaultListableBeanFactory beanFactory = unwrapDefaultListableBeanFactory(registry);
        if (beanFactory != null) {
            if (!(beanFactory.getDependencyComparator() instanceof AnnotationAwareOrderComparator)) {
                beanFactory.setDependencyComparator(AnnotationAwareOrderComparator.INSTANCE);
            }

            if (!(beanFactory.getAutowireCandidateResolver() instanceof ContextAnnotationAutowireCandidateResolver)) {
                beanFactory.setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver());
            }
        }

        Set<BeanDefinitionHolder> beanDefs = new LinkedHashSet(8);
        RootBeanDefinition def;
//这里会涉及到三个非常重要的BeanPostProcessor
//1、ConfigurationClassPostProcessor基于注解的Spring基本都是依靠它来做Bean的实例化
//2、AutowiredAnnotationBeanPostProcessor 用于解析@Autowired和@Value注解
//3、CommonAnnotationBeanPostProcessor 用于解析@PostConstruct @PreDestroy注解
        if (!registry.containsBeanDefinition("org.springframework.context.annotation.internalConfigurationAnnotationProcessor")) {
            def = new RootBeanDefinition(ConfigurationClassPostProcessor.class);
            def.setSource(source);
            beanDefs.add(registerPostProcessor(registry, def, "org.springframework.context.annotation.internalConfigurationAnnotationProcessor"));
        }

        if (!registry.containsBeanDefinition("org.springframework.context.annotation.internalAutowiredAnnotationProcessor")) {
            def = new RootBeanDefinition(AutowiredAnnotationBeanPostProcessor.class);
            def.setSource(source);
            beanDefs.add(registerPostProcessor(registry, def, "org.springframework.context.annotation.internalAutowiredAnnotationProcessor"));
        }

        if (jsr250Present && !registry.containsBeanDefinition("org.springframework.context.annotation.internalCommonAnnotationProcessor")) {
            def = new RootBeanDefinition(CommonAnnotationBeanPostProcessor.class);
            def.setSource(source);
            beanDefs.add(registerPostProcessor(registry, def, "org.springframework.context.annotation.internalCommonAnnotationProcessor"));
        }

        if (jpaPresent && !registry.containsBeanDefinition("org.springframework.context.annotation.internalPersistenceAnnotationProcessor")) {
            def = new RootBeanDefinition();

            try {
                def.setBeanClass(ClassUtils.forName("org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor", AnnotationConfigUtils.class.getClassLoader()));
            } catch (ClassNotFoundException var6) {
                throw new IllegalStateException("Cannot load optional framework class: org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor", var6);
            }

            def.setSource(source);
            beanDefs.add(registerPostProcessor(registry, def, "org.springframework.context.annotation.internalPersistenceAnnotationProcessor"));
        }

        if (!registry.containsBeanDefinition("org.springframework.context.event.internalEventListenerProcessor")) {
            def = new RootBeanDefinition(EventListenerMethodProcessor.class);
            def.setSource(source);
            beanDefs.add(registerPostProcessor(registry, def, "org.springframework.context.event.internalEventListenerProcessor"));
        }

        if (!registry.containsBeanDefinition("org.springframework.context.event.internalEventListenerFactory")) {
            def = new RootBeanDefinition(DefaultEventListenerFactory.class);
            def.setSource(source);
            beanDefs.add(registerPostProcessor(registry, def, "org.springframework.context.event.internalEventListenerFactory"));
        }

        return beanDefs;
    }

        在这个方法中,涉及到了三个非常重要的BeanPostProcessor的bd注册过程,分别为:

        1、ConfigurationClassPostProcessor 在基于注解的Spring及SpringBoot中,几乎所有类的注解收集和解析过程都是依靠它来完成。

        2、AutowiredAnnotationBeanPostProcessor 用于解析@Autowired和@Value注解,完成依赖注入过程。

        3、CommonAnnotationBeanPostProcessor 用于解析@PostConstruct和@PreDestory注解,在Bean实例化结束后及销毁前完成一些自定义的逻辑,这三个类特意在此标注一下,非常重要!!!

       至此,<context:component-scan>标签的整个解析过程完成,此时BeanDefinitionRegistry中应该包含所有带@Component注解的类以及这三个重要的类。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值