Spring源码分析——AnnotationConfigApplicationContext组件注册流程

工程搭建

Maven依赖:

<dependencies>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>5.3.5</version>
    </dependency>
</dependencies>

在项目下新建一个byx.test包,然后在里面添加ABConfig三个类:

public class A {
}

public class B {
}

@Component
public class Config {
}

AB是两个普通的类(没有标注Component)注解,Config标注了Component注解,所以理论上只有Config会被注册到容器中。

然后再添加一个Main类作为启动类:

public class Main {
    public static void main(String[] args) {
        ApplicationContext ctx = new AnnotationConfigApplicationContext("byx.test");
        // 输出容器中的所有bean的name
        for (String name : ctx.getBeanDefinitionNames()) {
            System.out.println(name);
        }
    }
}

main函数中,创建了一个AnnotationConfigApplicationContext,然后输出容器中所有bean的name。

最终的项目结构是这样的:

运行Main,控制台输出如下:

org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
config

可以看到,容器中一共有5个bean,其中四个带internal的都是Spring内部自带的,config则是我们之前定义的Config类,下面就来探究一下这些组件是如何被注册的。

AnnotationConfigApplicationContext组件注册流程

main函数的这一行加一个断点,并启动调试:

首先step into,然后多次step over,直到进入AnnotationConfigApplicationContext的构造函数:

继续step over,执行完this()调用:

这里分享一个调试Spring的小技巧,就是通过观察BeanFactory内部的beanDefinitionMap这个成员变量来分析组件注册的时机。beanDefinitionMap是一个ConcurrentHashMap,它的键是bean的name,值是对应的BeanDefinition。通过观察这个变量,我们就可以知道当前容器中所有已注册的bean信息。

现在把注意力放在调试器的Varieables面板,找到this.beanFactory.beanDefinitionMap这个变量。

可以看到,beanDefinitionMap的大小为4,里面已经有了四个bean:

这四个bean都是Spring内部自带的组件,由此可推测,Spring内部自带的组件的注册是在this()调用中,即AnnotationConfigApplicationContext的默认构造函数中完成的,

继续step over,执行完scan(basePackages)这行后,发现beanDefinitionMap的大小变成了5,增加了一个name为config的bean,正是我们自定义的Config类(该类被Component注解标注):

由此可推测,Component注解标注的类是在scan(basePackages)调用中被注册的。从方法名可以推测,其内部执行了一个包扫描的操作。

Spring内置组件的注册

回到AnnotationConfigApplicationContext的构造函数:

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

从上面的分析可以知道,AnnotationConfigApplicationContext在它的默认构造函数中注册内部组件,即this()调用,实现如下:

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

使用调试器跟踪,同时注意beanDefinitionMap的变化,发现注册操作发生在this.reader = new AnnotatedBeanDefinitionReader(this)这行代码中,所以直接查看AnnotatedBeanDefinitionReader的构造函数:

public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry) {
    this(registry, getOrCreateEnvironment(registry));
}

继续进入另一个构造函数:

public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry, Environment environment) {
    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, null);
    AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
}

真正的注册操作发生在AnnotationConfigUtilsregisterAnnotationConfigProcessors方法中:

public static void registerAnnotationConfigProcessors(BeanDefinitionRegistry registry) {
    registerAnnotationConfigProcessors(registry, null);
}

继续进入registerAnnotationConfigProcessors重载方法,终于看到了核心代码(省略了一部分无关紧要的内容):

public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors(
        BeanDefinitionRegistry registry, @Nullable Object source) {
    ...
    Set<BeanDefinitionHolder> beanDefs = new LinkedHashSet<>(8);

    // 注册org.springframework.context.annotation.internalConfigurationAnnotationProcessor
    // ConfigurationClassPostProcessor用来处理Configuration注解
    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));
    }

    // 注册org.springframework.context.annotation.internalAutowiredAnnotationProcessor
    // AutowiredAnnotationBeanPostProcessor用来处理Autowired注解
    if (!registry.containsBeanDefinition(AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME)) {
        RootBeanDefinition def = new RootBeanDefinition(AutowiredAnnotationBeanPostProcessor.class);
        def.setSource(source);
        beanDefs.add(registerPostProcessor(registry, def, AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME));
    }
    ...
    // 注册org.springframework.context.event.internalEventListenerProcessor
    // 与EventListener有关
    if (!registry.containsBeanDefinition(EVENT_LISTENER_PROCESSOR_BEAN_NAME)) {
        RootBeanDefinition def = new RootBeanDefinition(EventListenerMethodProcessor.class);
        def.setSource(source);
        beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_PROCESSOR_BEAN_NAME));
    }

    // 注册org.springframework.context.event.internalEventListenerFactory
    // 还是与EventListener有关
    if (!registry.containsBeanDefinition(EVENT_LISTENER_FACTORY_BEAN_NAME)) {
        RootBeanDefinition def = new RootBeanDefinition(DefaultEventListenerFactory.class);
        def.setSource(source);
        beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_FACTORY_BEAN_NAME));
    }

    return beanDefs;
}

registerAnnotationConfigProcessors方法内部注册了我们在控制台输出中看到的四个Spring内置组件。

Component注解的处理

回到AnnotationConfigApplicationContext的构造函数:

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

从上面的分析可以知道,scan(basePackages)这个调用负责扫描并注册被Component标注的bean,该方法的实现如下:

public void scan(String... basePackages) {
    Assert.notEmpty(basePackages, "At least one base package must be specified");
    StartupStep scanPackages = this.getApplicationStartup().start("spring.context.base-packages.scan")
            .tag("packages", () -> Arrays.toString(basePackages));
    this.scanner.scan(basePackages);
    scanPackages.end();
}

真正干活的是this.scanner.scan(basePackages)这个调用,其中this.scanner是一个ClassPathBeanDefinitionScanner的实例,它在AnnotationConfigApplicationContext的默认构造函数中被初始化:

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); // 初始化scanner
}

ClassPathBeanDefinitionScannerscan方法实现如下:

public int scan(String... basePackages) {
    int beanCountAtScanStart = this.registry.getBeanDefinitionCount();

    doScan(basePackages);

    // Register annotation config processors, if necessary.
    if (this.includeAnnotationConfig) {
        AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
    }

    return (this.registry.getBeanDefinitionCount() - beanCountAtScanStart);
}

scan方法内部调用了doScan方法,同时还记录了bean数量的改变量。doScan方法实现如下:

// basePackages就是我们在main函数中构造AnnotationConfigApplicationContext时传入的包名
// 从这里也可以看出,我们可以同时传入多个包名
protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
    Assert.notEmpty(basePackages, "At least one base package must be specified");
	Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<>();
    // 遍历每个包名
    for (String basePackage : basePackages) {
        // 寻找每个包下符合条件的类,并包装成BeanDefinition
        Set<BeanDefinition> candidates = findCandidateComponents(basePackage);
        // 遍历找到的每个BeanDefinition
        for (BeanDefinition candidate : candidates) {
            // 设置scope属性
            ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);
            candidate.setScope(scopeMetadata.getScopeName());
            // 生成beanName
            String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);
            // 设置一些默认属性
            if (candidate instanceof AbstractBeanDefinition) {
                postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);
            }
            // 处理Lazy、Primary、DependsOn、Role、Description这些注解
            if (candidate instanceof AnnotatedBeanDefinition) {
                AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);
            }
            // 把BeanDefinition包装成BeanDefinitionHolder
            if (checkCandidate(beanName, candidate)) {
                BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
                definitionHolder =
                        AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
                beanDefinitions.add(definitionHolder);
                // 真正执行注册操作
                registerBeanDefinition(definitionHolder, this.registry);
            }
        }
    }
    // 返回所有BeanDefinitionHolder
    return beanDefinitions;
}

doScan方法是注册bean的核心逻辑,它遍历每个传入的包名,通过调用findCandidateComponents方法来获取每个包下满足条件的bean,然后进行一些必要的设置,最后调用registerBeanDefinition方法完成注册操作。

findCandidateComponents方法的实现如下:

public Set<BeanDefinition> findCandidateComponents(String basePackage) {
    if (this.componentsIndex != null && indexSupportsIncludeFilters()) {
        return addCandidateComponentsFromIndex(this.componentsIndex, basePackage);
    }
    else {
        return scanCandidateComponents(basePackage);
    }
}

scanCandidateComponents方法的实现如下:

private Set<BeanDefinition> scanCandidateComponents(String basePackage) {
    Set<BeanDefinition> candidates = new LinkedHashSet<>();
    try {
        // 将包名转换成一个资源url
        String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
                resolveBasePackage(basePackage) + '/' + this.resourcePattern;
        // 读取资源
        Resource[] resources = getResourcePatternResolver().getResources(packageSearchPath);
        boolean traceEnabled = logger.isTraceEnabled();
        boolean debugEnabled = logger.isDebugEnabled();
        // 遍历所有资源,每个资源表示一个.class文件
        for (Resource resource : resources) {
            if (traceEnabled) {
                logger.trace("Scanning " + resource);
            }
            if (resource.isReadable()) {
                try {
                    // 获取class的元数据,包括注解的信息
                    MetadataReader metadataReader = getMetadataReaderFactory().getMetadataReader(resource);
                    // 判断是否满足条件
                    if (isCandidateComponent(metadataReader)) {
                        // 构造BeanDefinition
                        ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);
                        sbd.setSource(resource);
                        if (isCandidateComponent(sbd)) {
                            if (debugEnabled) {
                                logger.debug("Identified candidate component class: " + resource);
                            }
                            candidates.add(sbd);
                        }
                        else {
                            if (debugEnabled) {
                                logger.debug("Ignored because not a concrete top-level class: " + resource);
                            }
                        }
                    }
                    else {
                        if (traceEnabled) {
                            logger.trace("Ignored because not matching any filter: " + resource);
                        }
                    }
                }
                catch (Throwable ex) {
                    throw new BeanDefinitionStoreException(
                            "Failed to read candidate component class: " + resource, ex);
                }
            }
            else {
                if (traceEnabled) {
                    logger.trace("Ignored because not readable: " + resource);
                }
            }
        }
    }
    catch (IOException ex) {
        throw new BeanDefinitionStoreException("I/O failure during classpath scanning", ex);
    }
    // 返回所有满足条件的BeanDefinition
    return candidates;
}

scanCandidateComponents方法使用Spring内置的资源读取机制读取指定包下的所有class文件,然后转换成MetadataReader,并传入isCandidateComponent方法判断是否满足要求,如果满足要求则加入isCandidateComponent集合。

isCandidateComponent方法的实现如下:

protected boolean isCandidateComponent(MetadataReader metadataReader) throws IOException {
    for (TypeFilter tf : this.excludeFilters) {
        if (tf.match(metadataReader, getMetadataReaderFactory())) {
            return false;
        }
    }
    for (TypeFilter tf : this.includeFilters) {
        if (tf.match(metadataReader, getMetadataReaderFactory())) {
            return isConditionMatch(metadataReader);
        }
    }
    return false;
}

isCandidateComponent方法通过excludeFiltersincludeFilters两个集合来对MetadataReader进行过滤。在调试中可以发现,includeFilters包含了一个Component注解的过滤器,所以可以过滤出标注了Component的类。

如果使用调试器调试程序,可以发现,isCandidateComponent方法只会对Config类返回true,而对其他类(ABMain)都返回false

includeFilters的初始化是在org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider#registerDefaultFilters方法中被初始化的(ClassPathScanningCandidateComponentProviderClassPathBeanDefinitionScanner的父类):

protected void registerDefaultFilters() {
    this.includeFilters.add(new AnnotationTypeFilter(Component.class));
    ...
}

到此,Component注解的处理过程就分析完了。

原文地址:https://www.cnblogs.com/baiyuxuan/p/14953165.html