Spring组件扫描原理解析

Spring组件扫描原理解析

一、概述

用一幅图来对两种方式配置Bean的组件扫描进行一个总结:

二、原理剖析

通过之前的学习我们知道只要是将Bean放到了BeanDefinitionMap中,那么就势必会经过Spring的那套Bean的生命周期,就势必会创建Bean。

2.1xml组件扫描方式

首先我们在xml中是通过这段代码来进行组件扫描的,扫描指定的基本包及其子包下的类,识别使用@Component注解:

java 复制代码
<context:component-scan base-package="com.itheima"/>

依据之前学习的命名空间的知识我们知道,通过命名空间是可以找到它对应的Handler处理器的,命名空间:

java 复制代码
xmlns:context="http://www.springframework.org/schema/context"

对应的Handler处理器:

java 复制代码
http\://www.springframework.org/schema/context=org.springframework.context.config.ContextNamespaceHandler
http\://www.springframework.org/schema/jee=org.springframework.ejb.config.JeeNamespaceHandler
http\://www.springframework.org/schema/lang=org.springframework.scripting.config.LangNamespaceHandler
http\://www.springframework.org/schema/task=org.springframework.scheduling.config.TaskNamespaceHandler
http\://www.springframework.org/schema/cache=org.springframework.cache.config.CacheNamespaceHandler

进入ContextNamespaceHandler:

java 复制代码
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//

package org.springframework.context.config;

import org.springframework.beans.factory.xml.NamespaceHandlerSupport;
import org.springframework.context.annotation.AnnotationConfigBeanDefinitionParser;
import org.springframework.context.annotation.ComponentScanBeanDefinitionParser;

public class ContextNamespaceHandler extends NamespaceHandlerSupport {
    public ContextNamespaceHandler() {
    }

    public void init() {
        this.registerBeanDefinitionParser("property-placeholder", new PropertyPlaceholderBeanDefinitionParser());
        this.registerBeanDefinitionParser("property-override", new PropertyOverrideBeanDefinitionParser());
        this.registerBeanDefinitionParser("annotation-config", new AnnotationConfigBeanDefinitionParser());
        this.registerBeanDefinitionParser("component-scan", new ComponentScanBeanDefinitionParser());
        this.registerBeanDefinitionParser("load-time-weaver", new LoadTimeWeaverBeanDefinitionParser());
        this.registerBeanDefinitionParser("spring-configured", new SpringConfiguredBeanDefinitionParser());
        this.registerBeanDefinitionParser("mbean-export", new MBeanExportBeanDefinitionParser());
        this.registerBeanDefinitionParser("mbean-server", new MBeanServerBeanDefinitionParser());
    }
}

进入component-scan对应的ComponentScanBeanDefinitionParser,看它的parse解析方法:

java 复制代码
 @Nullable
    public BeanDefinition parse(Element element, ParserContext parserContext) {
        String basePackage = element.getAttribute("base-package");
        basePackage = parserContext.getReaderContext().getEnvironment().resolvePlaceholders(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;
    }

进入ClassPathBeanDefinitionScanner的doScan方法,重点看这:

java 复制代码
 if (this.checkCandidate(beanName, candidate)) {
                    BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
                    definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
                    beanDefinitions.add(definitionHolder);
                    this.registerBeanDefinition(definitionHolder, this.registry);
                }

执行到BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);时可以看到BeanName是OtherBean3,BeanDefinitionMap为空;执行完this.registerBeanDefinition(definitionHolder, this.registry);,OtherBean3就注入了BeanDefinitionMap:

由此可见xml组件扫描方式是将Bean直接放到BeanDefinitionMap中实现创建Bean的,并没有通过BeanFactoryPostProcessor。

2.2注解方式主键扫描

首先先是进入AnnotationConfigApplicationContext类:

java 复制代码
public class AnnotationConfigApplicationContext extends GenericApplicationContext implements AnnotationConfigRegistry {
    private final AnnotatedBeanDefinitionReader reader;
    private final ClassPathBeanDefinitionScanner scanner;

    public AnnotationConfigApplicationContext() {
        StartupStep createAnnotatedBeanDefReader = this.getApplicationStartup().start("spring.context.annotated-bean-reader.create");
        this.reader = new AnnotatedBeanDefinitionReader(this);
        createAnnotatedBeanDefReader.end();
        this.scanner = new ClassPathBeanDefinitionScanner(this);
    }

    public AnnotationConfigApplicationContext(DefaultListableBeanFactory beanFactory) {
        super(beanFactory);
        this.reader = new AnnotatedBeanDefinitionReader(this);
        this.scanner = new ClassPathBeanDefinitionScanner(this);
    }

    public AnnotationConfigApplicationContext(Class<?>... componentClasses) {
        this();
        this.register(componentClasses);
        this.refresh();
    }

    public AnnotationConfigApplicationContext(String... basePackages) {
        this();
        this.scan(basePackages);
        this.refresh();
    }

直接进入this(),

java 复制代码
public AnnotationConfigApplicationContext() {
        StartupStep createAnnotatedBeanDefReader = this.getApplicationStartup().start("spring.context.annotated-bean-reader.create");
        this.reader = new AnnotatedBeanDefinitionReader(this);
        createAnnotatedBeanDefReader.end();
        this.scanner = new ClassPathBeanDefinitionScanner(this);
    }

进入AnnotatedBeanDefinitionReader,之前xml的形式是XmlBeanDefinitionReader:

java 复制代码
public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry) {
        this(registry, getOrCreateEnvironment(registry));
    }

    public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry, Environment environment) {
        this.beanNameGenerator = AnnotationBeanNameGenerator.INSTANCE;
        this.scopeMetadataResolver = new AnnotationScopeMetadataResolver();
        Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
        Assert.notNull(environment, "Environment must not be null");
        this.registry = registry;
        this.conditionEvaluator = new ConditionEvaluator(registry, environment, (ResourceLoader)null);
        AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
    }  

再是进入**AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);**中的registerAnnotationConfigProcessors:

java 复制代码
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);
        if (!registry.containsBeanDefinition("org.springframework.context.annotation.internalConfigurationAnnotationProcessor")) {
            RootBeanDefinition 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")) {
            RootBeanDefinition 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")) {
            RootBeanDefinition 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")) {
            RootBeanDefinition def = new RootBeanDefinition();

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

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

        if (!registry.containsBeanDefinition("org.springframework.context.event.internalEventListenerProcessor")) {
            RootBeanDefinition 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")) {
            RootBeanDefinition def = new RootBeanDefinition(DefaultEventListenerFactory.class);
            def.setSource(source);
            beanDefs.add(registerPostProcessor(registry, def, "org.springframework.context.event.internalEventListenerFactory"));
        }

        return beanDefs;
    }

在这里会注册六个if中的Bean进入BeanDefinitionMap当中:

每执行完一次return beanDefs就是注册一个。再进入ConfigurationClassPostProcessor.class(因为是注解形式的组件扫描),看到postProcessBeanDefinitionRegistry中的parser.parse(candidates);的parse方法,关注与parse相关的:

java 复制代码
for(BeanDefinitionHolder holder : this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName())) {

继续推进,看componentScanParser的parse方法:

java 复制代码
ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(this.registry, componentScan.getBoolean("useDefaultFilters"), this.environment, this.resourceLoader);

是否有一种似曾相识燕归来的感觉呢?哈哈,实际上这是和xml配置组件扫描是一致的啦,接下来就是老套路了,继续看doscan,由此进入:

java 复制代码
 return scanner.doScan(StringUtils.toStringArray(basePackages));
java 复制代码
  if (this.checkCandidate(beanName, candidate)) {
                    BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
                    definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
                    beanDefinitions.add(definitionHolder);
                    this.registerBeanDefinition(definitionHolder, this.registry);

一样的逻辑定义definitionHolder,使用BeanDefinitionRegistry的registerBeanDefinition(definitionHolder进行注册Bean到BeanDefinitionMap当中,完结了。

相关推荐
知识即是力量ol2 小时前
口语八股——Spring 面试实战指南(二):事务管理篇、Spring MVC 篇、Spring Boot 篇、Bean生命周期篇
spring·面试·mvc·springboot·八股·事务管理·bean生命周期
让我上个超影吧2 小时前
天机学堂——领取优惠券优化
java
输出输入2 小时前
Java Swing和JavaFX用哪个好
java·前端
星火开发设计2 小时前
C++ 异常处理:try-catch-throw 的基本用法
java·开发语言·jvm·c++·学习·知识·对象
没有bug.的程序员2 小时前
分布式配置深潜:Spring Cloud Config 与 Git 集成内核、版本回滚机制与多环境治理实战指南
java·分布式·git·spring cloud·分布式配置·版本回滚
好家伙VCC2 小时前
# 发散创新:基于ARCore的实时3D物体识别与交互开发实战 在增强现实(
java·python·3d·ar·交互
清水白石0082 小时前
函数签名内省实战:打造通用参数验证装饰器的完整指南
java·linux·数据库
程序员良许2 小时前
防火墙和入侵测试
后端
明月_清风2 小时前
从 JS 到 C++/Rust:利用 N-API 构建 Node.js 高性能扩展的底层闭环
后端