Spring IOC 初始化刷新流程二:obtainFreshBeanFactory()

Spring IOC 初始化刷新流程:https://www.cnblogs.com/jhxxb/p/13609289.html

方法源码

public abstract class AbstractApplicationContext extends DefaultResourceLoader implements ConfigurableApplicationContext {
    // 销毁原工厂,重新创建一个 bean 工厂。
    // 主要工作是创建 DefaultListableBeanFactory 实例,解析配置文件,注册 Bean 的定义信息
    protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
        refreshBeanFactory();
        return getBeanFactory();
    }

其中 refreshBeanFactory() 是具体的刷新 BeanFactory

public abstract class AbstractRefreshableApplicationContext extends AbstractApplicationContext {
    @Override
    protected final void refreshBeanFactory() throws BeansException {
        // 判断是否已经存在 BeanFactory,存在则销毁所有 Beans,并且关闭 BeanFactory,避免重复加载 BeanFactory
        if (hasBeanFactory()) {
            destroyBeans();
            closeBeanFactory();
        }
        try {
            // 创建具体的 beanFactory,这里创建的是 DefaultListableBeanFactory,最重要的 beanFactory,spring 注册及加载 bean 就靠它
            DefaultListableBeanFactory beanFactory = createBeanFactory();
            beanFactory.setSerializationId(getId());

            // 把当前旧容器的一些配置值复制给新容器
            // 这两个属性值初始值为空:复写此方法即可 customizeBeanFactory
            customizeBeanFactory(beanFactory);

            // 这个就是最重要的了,加载所有的 Bean 配置信息,属于模版方法,由子类去实现加载的方式
            loadBeanDefinitions(beanFactory);
            this.beanFactory = beanFactory;
        } catch (IOException ex) {
            throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
        }
    }

    protected void customizeBeanFactory(DefaultListableBeanFactory beanFactory) {
        if (this.allowBeanDefinitionOverriding != null) {
            // 是否允对一个名字相同但 definition 不同进行重新注册,默认是 true
            beanFactory.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
        }
        if (this.allowCircularReferences != null) {
            // 是否允许 Bean 之间循环引用,默认是 true
            beanFactory.setAllowCircularReferences(this.allowCircularReferences);
        }
    }

createBeanFactory()

public abstract class AbstractRefreshableApplicationContext extends AbstractApplicationContext {
    protected DefaultListableBeanFactory createBeanFactory() {
        // 创建的时候就是 new 了一个工厂:DefaultListableBeanFactory,这个时候工厂里面所有东西都是默认值,很多还没有完成初始化属性的设置
        return new DefaultListableBeanFactory(getInternalParentBeanFactory());
    }

public abstract class AbstractApplicationContext extends DefaultResourceLoader implements ConfigurableApplicationContext {
    @Nullable
    protected BeanFactory getInternalParentBeanFactory() {
        // 找父 BeanFactory,若存在就返回,存在父容器就存在父的 BeanFactory
        return (getParent() instanceof ConfigurableApplicationContext ? ((ConfigurableApplicationContext) getParent()).getBeanFactory() : getParent());
    }

public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory implements ConfigurableListableBeanFactory, BeanDefinitionRegistry, Serializable {
    public DefaultListableBeanFactory(@Nullable BeanFactory parentBeanFactory) {
        super(parentBeanFactory);
    }

public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory implements AutowireCapableBeanFactory {
    public AbstractAutowireCapableBeanFactory(@Nullable BeanFactory parentBeanFactory) {
        this();
        // 设置父 BeanFactory,若存在的话
        setParentBeanFactory(parentBeanFactory);
    }

    public AbstractAutowireCapableBeanFactory() {
        super();
        // 这里是重点,注意 @Autowired 和它的关系。忽略自动装配。这里指定的都是接口。
        // ignoreDependencyInterface 的真正意思是在自动装配时,忽略指定接口的实现类中对外的依赖。
        // 举例来说,当 A 中有属性 B,那么当 Spring 在获取 A 的 Bean 的时候如果其属性 B 还没有初始化,那么 Spring 会自动初始化 B,
        // 这也是 Spring 中提供的一个重要特性。但是,某些情况下,B 不会被初始化,其中的一种情况就是 B 实现了 BeanNameAware 接口,Spring 中
        // 是这样介绍的:自动装配时忽略给定的依赖接口,典型应用是通过其他方式解析 Application 上下文注册依赖,类似于 BeanFactory 通
        // 过 BeanFactoryAware 进行注人或者 ApplicationContext 通过 ApplicationContextAware 进行注入。
        ignoreDependencyInterface(BeanNameAware.class);
        ignoreDependencyInterface(BeanFactoryAware.class);
        ignoreDependencyInterface(BeanClassLoaderAware.class);
    }

loadBeanDefinitions()

public class AnnotationConfigWebApplicationContext extends AbstractRefreshableWebApplicationContext implements AnnotationConfigRegistry {
    @Override
    protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) {
        // 这里很重要,初始化这个脚手架,其实就是直接 new 出实例
        AnnotatedBeanDefinitionReader reader = getAnnotatedBeanDefinitionReader(beanFactory);
        ClassPathBeanDefinitionScanner scanner = getClassPathBeanDefinitionScanner(beanFactory);

        // 生成 Bean 的名称生成器,如果自己没有 setBeanNameGenerator(可以自定义),这里目前为 null
        BeanNameGenerator beanNameGenerator = getBeanNameGenerator();
        if (beanNameGenerator != null) {
            reader.setBeanNameGenerator(beanNameGenerator);
            scanner.setBeanNameGenerator(beanNameGenerator);
            // 若我们注册了 beanName 生成器,那么就会注册进容器里面
            beanFactory.registerSingleton(AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR, beanNameGenerator);
        }

        // 这是给 reader 和 scanner 注册 scope 的解析器,此处为 null
        ScopeMetadataResolver scopeMetadataResolver = getScopeMetadataResolver();
        if (scopeMetadataResolver != null) {
            reader.setScopeMetadataResolver(scopeMetadataResolver);
            scanner.setScopeMetadataResolver(scopeMetadataResolver);
        }

        // 此处注意:componentClasses 和 basePackages 一般是选其一(当然看到此处,它们是可以并存的)
        // 我们可以自己指定 componentClasses 配置文件,同时也可以交给下面扫描
        if (!this.componentClasses.isEmpty()) {
            if (logger.isDebugEnabled()) {
                // 这里会把所有的配置文件输出 debug 日志
                logger.debug("Registering component classes: [" + StringUtils.collectionToCommaDelimitedString(this.componentClasses) + "]");
            }
            // 若是指明的 Bean,就交给 reader 中的 doRegisterBean 去解析每一个 Config Bean
            reader.register(ClassUtils.toClassArray(this.componentClasses));
        }

        // 也可以是包扫描的方式,扫描配置文件的 Bean
        if (!this.basePackages.isEmpty()) {
            if (logger.isDebugEnabled()) {
                // 输出对应的 debug 日志
                logger.debug("Scanning base packages: [" + StringUtils.collectionToCommaDelimitedString(this.basePackages) + "]");
            }
            // 这里很重要
            scanner.scan(StringUtils.toStringArray(this.basePackages));
        }

        // 此处的意思是,也可以以全类名的形式注册。比如可以调用 setConfigLocations 设置(在 xml 配置中使用较多),也可以是包路径
        String[] configLocations = getConfigLocations();
        if (configLocations != null) {
            for (String configLocation : configLocations) {
                try {
                    Class<?> clazz = ClassUtils.forName(configLocation, getClassLoader());
                    if (logger.isTraceEnabled()) {
                        logger.trace("Registering [" + configLocation + "]");
                    }
                    reader.register(clazz);
                } catch (ClassNotFoundException ex) {
                    if (logger.isTraceEnabled()) {
                        logger.trace("Could not load class for config location [" + configLocation + "] - trying package scan. " + ex);
                    }
                    // 发现不是全类名,就当作包扫描
                    int count = scanner.scan(configLocation);
                    if (count == 0 && logger.isDebugEnabled()) {
                        logger.debug("No component classes found for specified class/package [" + configLocation + "]");
                    }
                }
            }
        }
    }

现在 BeanFactory 已经创建了,并且 Config 配置文件的 Bean 定义已经注册完成了(注:其它单例 Bean 是还没有解析的)
显然,下面的步骤大都把 BeanFactory 传进去了,都是基于此 Bean 工厂的了

AnnotatedBeanDefinitionReader 和 ClassPathBeanDefinitionScanner

Spring 容器里通过 BeanDefinition 对象来表示 Bean,BeanDefinition 描述了 Bean 的配置信息。而 BeanDefinitionRegistry 接口提供了向容器注册,删除,获取 BeanDefinition 对象的方法。

简单来说,BeanDefinitionRegistry 可以用来管理 BeanDefinition,所以理解 AnnotationConfigApplicationContext 很关键,它是 spring 加载 bean,管理 bean 的最重要的类。

AnnotatedBeanDefinitionReader

public class AnnotationConfigWebApplicationContext extends AbstractRefreshableWebApplicationContext implements AnnotationConfigRegistry {
    protected AnnotatedBeanDefinitionReader getAnnotatedBeanDefinitionReader(DefaultListableBeanFactory beanFactory) {
        return new AnnotatedBeanDefinitionReader(beanFactory, getEnvironment());
    }

public class AnnotatedBeanDefinitionReader {
    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;

        // ConditionEvaluator 完成条件注解的判断,在后面的 Spring Boot 中有大量的应用
        this.conditionEvaluator = new ConditionEvaluator(registry, environment, null);
        // 这句会把一些自动注解处理器加入到 ApplicationContext 下的 BeanFactory 的 BeanDefinitions 中,也就是 Spring 中 Bean 的管理完全交给了 ApplicationContext
        AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
    }

    public void register(Class<?>... componentClasses) {
        for (Class<?> componentClass : componentClasses) {
            registerBean(componentClass);
        }
    }

    public void registerBean(Class<?> beanClass) {
        doRegisterBean(beanClass, null, null, null, null);
    }

    private <T> void doRegisterBean(Class<T> beanClass, @Nullable String name, @Nullable Class<? extends Annotation>[] qualifiers, @Nullable Supplier<T> supplier, @Nullable BeanDefinitionCustomizer[] customizers) {
        // 先把此实体类型转换为一个 BeanDefinition
        AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(beanClass);
        // abd.getMetadata() 元数据包括注解信息、是否内部类、类 Class 基本信息等等
        // 此处由 conditionEvaluator#shouldSkip 去过滤,此 Class 是否是配置类。
        // 大体逻辑为:必须有 @Configuration 修饰。然后解析一些 Condition 注解,看是否排除
        if (this.conditionEvaluator.shouldSkip(abd.getMetadata())) {
            return;
        }

        abd.setInstanceSupplier(supplier);
        // 解析 Scope
        ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(abd);
        abd.setScope(scopeMetadata.getScopeName());
        // 得到 Bean 的名称 一般为首字母小写(此处为 AnnotationBeanNameGenerator)
        String beanName = (name != null ? name : this.beanNameGenerator.generateBeanName(abd, this.registry));

        // 设定一些注解默认值,如 lazy、Primary 等等
        AnnotationConfigUtils.processCommonDefinitionAnnotations(abd);
        // 解析 qualifiers,若有此注解,则 primary 都成为 true 了
        if (qualifiers != null) {
            for (Class<? extends Annotation> qualifier : qualifiers) {
                if (Primary.class == qualifier) {
                    abd.setPrimary(true);
                } else if (Lazy.class == qualifier) {
                    abd.setLazyInit(true);
                } else {
                    abd.addQualifier(new AutowireCandidateQualifier(qualifier));
                }
            }
        }
        if (customizers != null) {
            // 自定义定制信息(一般都不需要)
            for (BeanDefinitionCustomizer customizer : customizers) {
                customizer.customize(abd);
            }
        }

        // 下面会解析 Scope 是否需要代理,最后把这个 Bean 注册进去
        BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd, beanName);
        definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
        BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);
    }

AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry)

我们要用一些注解比如:@Autowired/@Required/@Resource 都依赖于各种各样的 BeanPostProcessor 来解析(AutowiredAnnotation、RequiredAnnotation、CommonAnnotationBeanPostProcessor 等)

但是向这种非常常用的,让调用者自己去申明,显然使用起来就过重了。所以 Spring 为我们提供了一种极为方便注册这些 BeanPostProcessor 的方式(若是 xml 方式,配置 <context:annotation- config/>,若是全注解驱动的 ApplicationContext,就默认会执行)

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

    public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors(BeanDefinitionRegistry registry, @Nullable Object source) {
        // 把 beanFactory 从 registry 里解析出来
        DefaultListableBeanFactory beanFactory = unwrapDefaultListableBeanFactory(registry);
        if (beanFactory != null) {
            if (!(beanFactory.getDependencyComparator() instanceof AnnotationAwareOrderComparator)) {
                beanFactory.setDependencyComparator(AnnotationAwareOrderComparator.INSTANCE);
            }
            // 相当于如果没有这个 AutowireCandidateResolver,就给设置一份 ContextAnnotationAutowireCandidateResolver
            if (!(beanFactory.getAutowireCandidateResolver() instanceof ContextAnnotationAutowireCandidateResolver)) {
                beanFactory.setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver());
            }
        }

        // 这里初始长度放 8,是因为大多数情况下,只会注册 6 个 BeanPostProcessor
        // BeanDefinitionHolder 解释:持有 name 和 aliases,为注册做准备
        Set<BeanDefinitionHolder> beanDefs = new LinkedHashSet<>(8);

        // ConfigurationClassPostProcessor 是一个 BeanFactoryPostProcessor 和 BeanDefinitionRegistryPostProcessor 处理器,
        // BeanDefinitionRegistryPostProcessor 的处理方法能处理 @Configuration 等注解。
        // ConfigurationClassPostProcessor#postProcessBeanDefinitionRegistry() 方法内部处理 @Configuration,@Import,@ImportResource 和类内部的 @Bean。
        // ConfigurationClassPostProcessor 类继承了 BeanDefinitionRegistryPostProcessor。BeanDefinitionRegistryPostProcessor 类继承了 BeanFactoryPostProcessor。
        // 通过 BeanDefinitionRegistryPostProcessor 可以创建一个特别的后置处理器来将 BeanDefinition 添加到 BeanDefinitionRegistry 中。
        // 它和 BeanPostProcessor 不同,BeanPostProcessor 只是在 Bean 初始化的时候有个钩子让我们加入一些自定义操作;
        // 而 BeanDefinitionRegistryPostProcessor 可以让我们在 BeanDefinition 中添加一些自定义操作。
        // 在 Mybatis 与 Spring 的整合中,就利用到了 BeanDefinitionRegistryPostProcessor 来对 Mapper 的 BeanDefinition 进行了后置的自定义处理。
        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));
        }

        // AutowiredAnnotationBeanPostProcessor 是用来处理 @Autowired 注解和 @Value 注解的
        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));
        }

        // Check for JSR-250 support, and if present add the CommonAnnotationBeanPostProcessor.
        // CommonAnnotationBeanPostProcessor 提供对 JSR-250 规范注解的支持
        // @javax.annotation.Resource、@javax.annotation.PostConstruct 和 @javax.annotation.PreDestroy 等
        if (jsr250Present && !registry.containsBeanDefinition(COMMON_ANNOTATION_PROCESSOR_BEAN_NAME)) {
            RootBeanDefinition def = new RootBeanDefinition(CommonAnnotationBeanPostProcessor.class);
            def.setSource(source);
            beanDefs.add(registerPostProcessor(registry, def, COMMON_ANNOTATION_PROCESSOR_BEAN_NAME));
        }

        // Check for JPA support, and if present add the PersistenceAnnotationBeanPostProcessor.
        // 若导入了对 JPA 的支持,那就注册 JPA 相关注解的处理器
        if (jpaPresent && !registry.containsBeanDefinition(PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME)) {
            RootBeanDefinition def = new RootBeanDefinition();
            try {
                def.setBeanClass(ClassUtils.forName(PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME, AnnotationConfigUtils.class.getClassLoader()));
            } catch (ClassNotFoundException ex) {
                throw new IllegalStateException("Cannot load optional framework class: " + PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME, ex);
            }
            def.setSource(source);
            beanDefs.add(registerPostProcessor(registry, def, PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME));
        }

        // 下面两个类,是 Spring4.2 之后加入进来的,为了更好的使用 Spring 的事件而提供支持
        // EventListenerMethodProcessor 提供 @PersistenceContext 和 @EventListener 的支持。
        // @EventListener 是在 spring4.2 之后出现的,可以在一个 Bean 的方法上使用 @EventListener 注解来自动注册一个 ApplicationListener。
        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));
        }

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

Note:内部定义的 class 都是带 internal 的

至此,AnnotatedBeanDefinitionReader 初始化完毕,总结一下:

AnnotatedBeanDefinitionReade 读取器用来加载 class 类型的配置,在它初始化的时候,会预先注册一些 BeanPostProcessor 和 BeanFactoryPostProcessor,这些处理器会在接下来的 spring 初始化流程中被调用。

ClassPathBeanDefinitionScanner

public class AnnotationConfigWebApplicationContext extends AbstractRefreshableWebApplicationContext implements AnnotationConfigRegistry {
    protected ClassPathBeanDefinitionScanner getClassPathBeanDefinitionScanner(DefaultListableBeanFactory beanFactory) {
        return new ClassPathBeanDefinitionScanner(beanFactory, true, getEnvironment());
    }

public class ClassPathBeanDefinitionScanner extends ClassPathScanningCandidateComponentProvider {
    public ClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry, boolean useDefaultFilters, Environment environment) {
        this(registry, useDefaultFilters, environment, (registry instanceof ResourceLoader ? (ResourceLoader) registry : null));
    }

    public ClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry, boolean useDefaultFilters, Environment environment, @Nullable ResourceLoader resourceLoader) {
        Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
        this.registry = registry;

        // useDefaultFilters 为 true,所以此处一般都会执行
        // 当然我们也可以设置为 false,比如 @ComponentScan 里就可以设置为 false,只扫描指定的注解和类等等
        if (useDefaultFilters) {
            registerDefaultFilters();
        }
        // 设置环境
        setEnvironment(environment);
        // 这里 resourceLoader 传值,还是我们的工厂。否则为 null
        setResourceLoader(resourceLoader);
    }

registerDefaultFilters()

public class ClassPathScanningCandidateComponentProvider implements EnvironmentCapable, ResourceLoaderAware {
    protected void registerDefaultFilters() {
        // 这里需要注意,默认情况下都是添加了 @Component 这个注解的
        //(相当于 @Service @Controller @Respository 等都会扫描,因为这些注解都属于 @Component)另外 @Configuration 也属于
        this.includeFilters.add(new AnnotationTypeFilter(Component.class));
        ClassLoader cl = org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider.class.getClassLoader();

        // 下面两个是兼容 JSR-250 的 @ManagedBean 和 JSR-330 的 @Named 注解
        try {
            this.includeFilters.add(new AnnotationTypeFilter(((Class<? extends Annotation>) ClassUtils.forName("javax.annotation.ManagedBean", cl)), false));
            logger.trace("JSR-250 'javax.annotation.ManagedBean' found and supported for component scanning");
        } catch (ClassNotFoundException ex) {
            // JSR-250 1.1 API (as included in Java EE 6) not available - simply skip.
        }
        try {
            this.includeFilters.add(new AnnotationTypeFilter(((Class<? extends Annotation>) ClassUtils.forName("javax.inject.Named", cl)), false));
            logger.trace("JSR-330 'javax.inject.Named' annotation found and supported for component scanning");
        } catch (ClassNotFoundException ex) {
            // JSR-330 API not available - simply skip.
        }

        // 所以,如果想 Spring 连你自定义的注解都扫描,自己实现一个 AnnotationTypeFilter 就可以
    }

ClassPathBeanDefinitionScanner 继承于 ClassPathScanningCandidateComponentProvider,它内部维护有两个 final 类型的 List:这两个对象在执行本类的 scanCandidateComponents() 方法时就会起作用。

public class ClassPathScanningCandidateComponentProvider implements EnvironmentCapable, ResourceLoaderAware {
    // 满足过滤规则的
    private final List<TypeFilter> includeFilters = new LinkedList<>();
    // 不满足过滤规则的
    private final List<TypeFilter> excludeFilters = new LinkedList<>();

    // 为 ResourcePatternResolver,MetadataReaderFactory 和 CandidateComponentsIndex 设定初始值
    @Override
    public void setResourceLoader(@Nullable ResourceLoader resourceLoader) {
        // ResourcePatternResolver 是一个接口,继承了 ResourceLoader,可以用来获取 Resource 实例。返回的实例为 PathMatchingResourcePatternResolver 类型
        this.resourcePatternResolver = ResourcePatternUtils.getResourcePatternResolver(resourceLoader);
        // MetadataReaderFactory 用于解析资源信息对应的元数据,这里返回的实例为:CachingMetadataReaderFactory,带有缓存的
        this.metadataReaderFactory = new CachingMetadataReaderFactory(resourceLoader);
        // Spring5 以后才有这句,优化了 bean 扫描
        this.componentsIndex = CandidateComponentsIndexLoader.loadIndex(this.resourcePatternResolver.getClassLoader());
    }

备注:若要使用 Spring5 的 componentsIndex 功能,需要添加额外 jar 包。这样子当工程重新编译的时候(编译期),会在自动生成 META-INF/spring.components。

然后我们在启动用 @ComponentScan 扫描时,直接读取这个文件即可,极大的提高了 Spring 启动的速度。而这期间,可以使用 Spring5.0 最新提供的注解 @Indexed 来配合使用。

之后只要运行工程发现这个文件都会直接使用它。可以通过环境变量或工程根目录的 spring.properties 中设置 spring.index.ignore=ture 来禁用这个功能

需要注意的是:这种方式也是存在缺陷的,具体缺陷请参考官方文档:https://docs.spring.io/spring/docs/current/spring-framework-reference/core.html#beans-scanning-index

至此,ClassPathBeanDefinitionScanner 初始化完毕,总结一下:

ClassPathBeanDefinitionScanner 是一个扫描指定类路径中注解 Bean 定义的扫描器,在它初始化的时候,会初始化一些需要被扫描的注解,初始化用于加载包下的资源的 Loader。

AnnotatedBeanDefinitionReader 和 ClassPathBeanDefinitionScanner 的初始化是 spring 上线文初始化的起点,很多预加载的类会在 spring 接下来的初始化中发挥重要作用。

包扫描的启动方式

很多时候我们会在 Spring 应用的配置类上标注如下注解

// 扫描包路径,spring 扫描除 controller 层以外的,spring 不可从子容器(spring mvc)中获取 bean
@ComponentScan(basePackages = {"spring.mvc"}, excludeFilters = {
        @ComponentScan.Filter(type = FilterType.ANNOTATION, classes = {Controller.class})
})
public class RootConfig {

// 扫描包,只扫描 controller 层,其他 bean 可从父容器(spring)中获取
@ComponentScan(basePackages = {"spring.mvc.controller"}, includeFilters = {
        @ComponentScan.Filter(type = FilterType.ANNOTATION, classes = {Controller.class})
}, useDefaultFilters = false)
public class SpringMvcConfig implements WebMvcConfigurer {

或者是 SpringBoot 应用

// 默认为启动类所在的包路径
@SpringBootApplication(scanBasePackages = {"com.ssm"})
public class SSMApplication {

这些都会触发包扫描,由上面提到的 ConfigurationClassPostProcessor 触发 ClassPathBeanDefinitionScanner 来处理,重点为 doScan() 方法,注:这里 ComponentScan 这个注解还没有被解析

public class ClassPathBeanDefinitionScanner extends ClassPathScanningCandidateComponentProvider {
    protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
        Assert.notEmpty(basePackages, "At least one base package must be specified");
        // 装载扫描到的 Bean
        Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<>();
        for (String basePackage : basePackages) {
            // 这个方法是最重点,会把该包下面所有的 Bean 都扫描进去,Spring5 和以前的处理方式不一样
            Set<BeanDefinition> candidates = findCandidateComponents(basePackage);
            for (BeanDefinition candidate : candidates) {
                // 拿到 Scope 元数据:此处为 singleton
                ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);
                candidate.setScope(scopeMetadata.getScopeName());
                // 生成 Bean 的名称,默认为首字母小写
                String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);

                // 此处扫描的 Bean为 ScannedGenericBeanDefinition.class 类型,所以肯定为 true
                if (candidate instanceof AbstractBeanDefinition) {
                    // 执行 postProcessBeanDefinition 添加些默认的 Bean 定义信息,并不是执行后置处理器
                    postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);
                }
                // 显然,此处也是 true
                if (candidate instanceof AnnotatedBeanDefinition) {
                    // 也是完善 Bean 的一些注解信息:例如 @Lazy、@Primary、@DependsOn、@Role、@Description
                    // @Role 注解用于 Bean 的分类分组,没有太大的作用
                    AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);
                }
                // 检查 Bean,比如
                // 如果 dao 包(一般配置的 basePakage 是这个)下的类是符合 MyBatis 要求的,则向 Spring IOC 容器中注册它的 BeanDefinition
                // 所以这步检查第三方 Bean 的时候有必要检查一下
                if (checkCandidate(beanName, candidate)) {
                    BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
                    // AnnotationConfigUtils 类的 applyScopedProxyMode 方法根据注解 Bean 定义类中配置的作用域 @Scope 注解的值,为 Bean 定义应用相应的代理模式,主要是在 Spring 面向切面编程(AOP)中使用
                    definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
                    beanDefinitions.add(definitionHolder);
                    // 注意:这里已经把 Bean 注册进去工厂了,所有 doScan() 方法不接收返回值,也是没有任何问题的
                    registerBeanDefinition(definitionHolder, this.registry);
                }
            }
        }
        return beanDefinitions;
    }

findCandidateComponents()

public class ClassPathBeanDefinitionScanner extends ClassPathScanningCandidateComponentProvider {
    public Set<BeanDefinition> findCandidateComponents(String basePackage) {
        // 上面说过了 CandidateComponentsIndex 是 Spring5 提供的优化扫描的功能
        // 这里编译器没有生成 META-INF/spring.components 索引文件,所以此处不会执行 Spring5 的扫描方式,(超大型项目才会使用 Spring5 的方式)
        if (this.componentsIndex != null && indexSupportsIncludeFilters()) {
            return addCandidateComponentsFromIndex(this.componentsIndex, basePackage);
        } else {
            // Spring5 之前的方式(绝大多数情况下,都是此方式)
            return scanCandidateComponents(basePackage);
        }
    }

    private Set<BeanDefinition> scanCandidateComponents(String basePackage) {
        Set<BeanDefinition> candidates = new LinkedHashSet<>();
        try {
            // 1.根据指定包名生成包搜索路径
            // 通过观察 resolveBasePackage() 方法的实现, 我们可以在设置 basePackage 时, 使用形如 ${} 的占位符, Spring会在这里进行替换,只要在 Enviroment 里面就行
            // 本次值为:classpath*:spring/mvc/controller/**/*.class
            String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX + resolveBasePackage(basePackage) + '/' + this.resourcePattern;

            // 2. 资源加载器加载搜索路径下(不包含 jar 包内的)所有的 .class 文件(这个方法,其实我们也可以使用),可能有上百个,然后进行筛选,解析类上的注解,以及过滤掉不是候选的类,并转换为 Resource[]
            // 真正干事的为:PathMatchingResourcePatternResolver#getResources 方法
            Resource[] resources = getResourcePatternResolver().getResources(packageSearchPath);
            boolean traceEnabled = logger.isTraceEnabled();
            boolean debugEnabled = logger.isDebugEnabled();
            // 这个 for 循环就是把一个个的 resource 组装成
            for (Resource resource : resources) {
                if (traceEnabled) {
                    logger.trace("Scanning " + resource);
                }
                // 文件必须可读,否则直接返回空
                if (resource.isReadable()) {
                    try {
                        // 读取类的注解信息和类信息,两大信息储存到 MetadataReader
                        MetadataReader metadataReader = getMetadataReaderFactory().getMetadataReader(resource);
                        // 根据 TypeFilter 过滤排除组件。没有标注 @Component 或者子注解的不属于候选组件,返回 false
                        // 注意:这里一般(默认处理的情况下)标注了默认注解的才会 true,默认注解就是 @Component 或者派生注解。还有 javax 的注解
                        if (isCandidateComponent(metadataReader)) {
                            // 把符合条件的类转换成 BeanDefinition
                            ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);
                            sbd.setSource(resource);
                            // 再次判断,如果是实体类,返回 true,如果是抽象类,但是抽象方法被 @Lookup 注解注释,返回 true
                            // 这和上面是个重载方法,个人觉得只在处理循环引用以及 @Lookup(例如一个单例 Bean 依赖另一个非单例 Bean)
                            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);
        }
        // 备注:此时 ComponentScan 这个注解还没有被解析
        return candidates;
    }

postProcessBeanDefinition()

public class ClassPathBeanDefinitionScanner extends ClassPathScanningCandidateComponentProvider {
    protected void postProcessBeanDefinition(AbstractBeanDefinition beanDefinition, String beanName) {
        // 为 Bean 定义执行些默认的信息
        // BeanDefinitionDefaults 是个标准的 JavaBean,有一些默认值
        beanDefinition.applyDefaults(this.beanDefinitionDefaults);
        // 自动依赖注入匹配路径(此处为 null,不进来)
        if (this.autowireCandidatePatterns != null) {
            beanDefinition.setAutowireCandidate(PatternMatchUtils.simpleMatch(this.autowireCandidatePatterns, beanName));
        }
    }

public abstract class AbstractBeanDefinition extends BeanMetadataAttributeAccessor implements BeanDefinition, Cloneable {
    public void applyDefaults(BeanDefinitionDefaults defaults) {
        Boolean lazyInit = defaults.getLazyInit();
        if (lazyInit != null) {
            setLazyInit(lazyInit);
        }
        setAutowireMode(defaults.getAutowireMode());
        setDependencyCheck(defaults.getDependencyCheck());
        setInitMethodName(defaults.getInitMethodName());
        setEnforceInitMethod(false);
        setDestroyMethodName(defaults.getDestroyMethodName());
        setEnforceDestroyMethod(false);
    }

至此,扫描的 Bean 就全部注册完成了


https://blog.csdn.net/f641385712/article/details/88059145

原文地址:https://www.cnblogs.com/jhxxb/p/13950058.html