【一】springboot启动源码 - invokeBeanFactoryPostProcessors - (上)

说明

SpringBoot 版本 2.7.1

SpringApplication.run(),refresh()调用之前解析

  1. SpringApplication在构造方法时,就会读取META-INF/spring.factories的类,缓存到SpringFactoriesLoader中(这是Spring的SPI),注意这里的缓存不仅仅只有org.springframework.boot.autoconfigure.EnableAutoConfiguration,包括文件中所有key-value
    在这里插入图片描述
    在这里插入图片描述
    缓存是一个静态变量
    在这里插入图片描述

  2. SpringApplication第298行,通过SPI从META-INF/spring.factories获取org.springframework.boot.SpringApplicationRunListener的实现类并加载
    在这里插入图片描述
    通过构造器创建自定义RunListener实例
    在这里插入图片描述
    进入到自定义RunListener的构造方法
    在这里插入图片描述

  3. 第299行,通过spring.factories获取的所有SpringApplicationRunListener的实现类,并调用start方法
    在这里插入图片描述
    在这里插入图片描述

  4. SpringApplication第302行,创建spring环境配置类,默认环境变量实现类为ApplicationServletEnvironme
    在这里插入图片描述ApplicationServletEnvironment的抽象父类为AbstractEnvironment,他的成员变量MutablePropertySources propertySources是环境变量核心。包含了List<PropertySource<?>> propertySourceList
    在这里插入图片描述
    PropertySource类结构
    在这里插入图片描述
    继续回到ApplicationServletEnvironment的构造方法创建,在默认调用抽象父类的构造中,执行了customizePropertySources(MutablePropertySources propertySources)方法
    在这里插入图片描述
    这个方法由ApplicationServletEnvironment的直接父类StandardServletEnvironment来实现,添加了两个默认的propertySource,再去调用StandardServletEnvironment的直接父类StandardEnvironment的customizePropertySources(MutablePropertySources propertySources)方法。再添加两个默认的propertySource,这里就包含了系统配置System.getProperties()和系统运行环境System.getenv()
    在这里插入图片描述
    以上只是prepareEnvironment方法的第341行逻辑,341行之后,还会添加一些propertySource、调用省略SpringApplicationRunListener的environmentPrepared方法等
    在这里插入图片描述
    完成spring环境配置类创建

  5. 创建IOC核心ApplicationContext,第305行
    context核心变量的核心包括:
    a. List beanFactoryPostProcessors
    b. ConfigurableEnvironment environment
    c. DefaultListableBeanFactory beanFactory
    在这里插入图片描述
    默认ApplicationContext的实现类是AnnotationConfigServletWebServerApplicationContext
    在这里插入图片描述
    它的间接父类是GenericApplicationContext,构造方法中初始化了beanFactory,这里与spring的ClassPathXmlApplicationContext有区别,ClassPathXmlApplicationContext是在refresh执行时才创建beanFactory,而GenericApplicationContext是在refresh之前
    以上为创建ApplicationContext逻辑。

  6. 进行ApplicationContext赋值处理,SpringApplication第307行prepareContext方法
    在这里插入图片描述
    进入prepareContext方法,这里赋值了environment、添加默认类到IOC容器(beanFactory的间接父类DefaultSingletonBeanRegistry中的singletonObjects,作为一级缓存)、设置循环依赖状态、添加默认BeanFactoryPostProcessor
    在这里插入图片描述
    调用SpringApplicationRunListener的contextPrepared、contextLoaded方法
    在这里插入图片描述
    在这里插入图片描述

  7. SpringApplication第308行,核心方法refreshContext(context);
    在这里插入图片描述
    调用context.refresh(),由AnnotationConfigServletWebServerApplicationContext的间接抽象父类AbstractApplicationContext来实现。

Context.refresh()调用方法解析

  1. AbstractApplicationContext第553行obtainFreshBeanFactory()
    在这里插入图片描述

这里的实现很简单,只是返回了beanFactory对象(如果context是用spring的ClassPathXmlApplicationContext,会在这里进行beanDefinition的构建,这里不做深入区别讨论)

在这里插入图片描述

  1. AbstractApplicationContext第556行,prepareBeanFactory

Prepare the bean factory for use in this context.

在这里插入图片描述
会默认添加一些beanPostProcess实现(比如ApplicationContextAwareProcessor,用来判断bean是否实现了各种Aware接口,如果实现了,ApplicationContextAwareProcessor会在postProcessBeforeInitialization执行回调)。
在这里插入图片描述

会默认注册一些单例bean到ioc容器(比如 environment、systemProperties、systemEnvironment等)。DefaultListableBeanFactory的父类DefaultSingletonBeanRegistry,里面的成员变量 Map<String, Object> singletonObjects,作为IOC容器用来存放单例对象,注册的单例bean会放在这里。
在这里插入图片描述

  1. AbstractApplicationContext第560行,postProcessBeanFactory

Allows post-processing of the bean factory in context subclasses.

在这里插入图片描述
由AnnotationConfigServletWebServerApplicationContext实现
在这里插入图片描述
super.postProcessBeanFactory(beanFactory)。会添加WebApplicationContextServletContextAwareProcessor到BeanPostProcessor

在这里插入图片描述

invokeBeanFactoryPostProcessors

AbstractApplicationContext第564行,invokeBeanFactoryPostProcessors。
这个方法会执行springboot的自动装配核心逻辑

Invoke factory processors registered as beans in the context.

在这里插入图片描述
在这里插入图片描述
PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors 方法
第112行invokeBeanDefinitionRegistryPostProcessors
在这里插入图片描述在这里执行BeanDefinitionRegistryPostProcessor的实现方法postProcessBeanDefinitionRegistry。
当前postProcessor是ConfigurationClassPostProcessor
在这里插入图片描述
在这里插入图片描述
进入ConfigurationClassPostProcessor.processConfigBeanDefinitions方法
从beanFactory的beanDefinitionMap中,目前beanDefinitionMap的数据只有初始化时候加入的,如下
在这里插入图片描述

接着第287行 ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory),会依次遍历判断是否有@Configuration注解,启动类因为有@SpringBootApplication,它引用了@SpringBootConfiguration,而@SpringBootConfiguration又引用了@Configuration。把符合要求的BeanDefinition封装成BeanDefinitionHolder(第288行),然后加入到 List configCandidates 集合中

configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));

通过过滤放这里configCandidates集合只有启动类
在这里插入图片描述

327Set<BeanDefinitionHolder> candidates = new LinkedHashSet<>(configCandidates);
332行
构建了一个
ConfigurationClassParser parser = new ConfigurationClassParser(
				this.metadataReaderFactory, this.problemReporter, this.environment,
				this.resourceLoader, this.componentScanBeanNameGenerator, registry);

processConfigBeanDefinitions方法第329-367行,递归遍历candidates集合,解析每一个BeanDefinitionHolder
第331行 parser.parse(candidates)
在这里插入图片描述
ConfigurationClassParser的parse方法,第175行
在这里插入图片描述
ConfigurationClassParser第206行,parse的重载方法
在这里插入图片描述
进入ConfigurationClassParser第225行,processConfigurationClass
第250行,开始处理@Configuration注解的类逻辑
在这里插入图片描述
进入doProcessConfigurationClass,可以看到这里针对类上的注解做了很多判断,是否有@Component、@PropertySource、@ComponentScan、@Import注解等
在这里插入图片描述
先看ConfigurationClassParser-doProcessConfigurationClass-272行,当类上有@Component注解时,判断是否有内部类,再递归判断内部类是否有@Component
在这里插入图片描述

在这里插入图片描述
ConfigurationClassParser-第276行,判断是否有@PropertySources注解
在这里插入图片描述
ConfigurationClassParser-第442行开始,processPropertySource 方法
先判断@PropertySource的value是否为空(这是必要配置),然后加载value的值为Resource对象
ConfigurationClassParser-第463行,factory.createPropertySource(name, new EncodedResource(resource, encoding)),这里的factory默认是DefaultPropertySourceFactory
在这里插入图片描述

ConfigurationClassParser-第479行,进入DefaultPropertySourceFactory.createPropertySource方法

在这里插入图片描述
会创建并返回ResourcePropertySource对象
ResourcePropertySource的构造方法如下,通过getNameForResource(resource.getResource()) 和 *PropertiesLoaderUtils.loadProperties(resource)方法构造成 String name 和 Properties source,继续调用父类构造方法
在这里插入图片描述
最终ResourcePropertySource的顶层抽象类为PropertySource。构造完成后返回
在这里插入图片描述
回到ConfigurationClassParser-463行,将构造返回的propertySource,再调用
addPropertySource(propertySource)*方法

在这里插入图片描述
ConfigurationClassParser-479行,addPropertySource方法
判断environment的propertySources是否已经包含了此propertySource,如果没有包含,添加到propertySources中
第505-510行,是用来判断插入propertySources的位置
在这里插入图片描述
回到ConfigurationClassParser-280行,处理完了@PropertySources的逻辑,继续往下
ConfigurationClassParser-289行,开始处理@ComponentScan逻辑,进入296行componentScanParser.parse
在这里插入图片描述
ComponentScanAnnotationParser-68行parse方法,初始化ClassPathBeanDefinitionScanner类,处理了basePackages的包扫描路径等
在这里插入图片描述
直接看到ComponentScanAnnotationParser-128行,ClassPathBeanDefinitionScanner scanner.doScan(StringUtils.toStringArray(basePackages));
在这里插入图片描述
进入ClassPathBeanDefinitionScanner-272行的doScan方法,入参为scanBasePackages的值
从275行开始,遍历所有basePackages,276行,从basePackage的值开始扫描符合要求的bean,并封装成BeanDefinition
在这里插入图片描述
由父类ClassPathScanningCandidateComponentProvider实现findCandidateComponents 方法,第311行
再进入316行 scanCandidateComponents(basePackage);
在这里插入图片描述
ClassPathScanningCandidateComponentProvider第416行开始
获取classpath下符合basePackage的 .class路径。如这里的: classpath:org/hopehomi/**/*.class
在这里插入图片描述
获取到该路径下所有的 *.class路径
在这里插入图片描述

tips: 
基于class扫描,我们可以自定义ResourceLoaderAware,或者直接继承ClassPathScanningCandidateComponentProvider。
使用ClassPathScanningCandidateComponentProviderclass加载能力


package org.hopehomi.core.tool.aware;

import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.context.ResourceLoaderAware;
import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternUtils;
import org.springframework.core.type.classreading.CachingMetadataReaderFactory;
import org.springframework.core.type.classreading.MetadataReader;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;

/**
 * @author Ledison
 * @date 2023/3/17
 */
public class HopeResourceLoaderAware extends ClassPathScanningCandidateComponentProvider implements ResourceLoaderAware{

    private ResourceLoader resourceLoader;
    private final String DEFAULT_RESOURCE_PATTERN = "/**/*.class";
    private ClassPathScanningCandidateComponentProvider provider;

    @Override
    public void setResourceLoader(ResourceLoader resourceLoader) {
        provider = new ClassPathScanningCandidateComponentProvider(true);
        provider.setResourceLoader(resourceLoader);
        this.resourceLoader = resourceLoader;
    }

    public Resource[] getPackagePathResources(String packagePath) throws IOException {
        ResourcePatternResolver resourcePatternResolver = ResourcePatternUtils.getResourcePatternResolver(resourceLoader);
        packagePath = packagePathParse(packagePath);
        // classpath*:org/hopehomi/**/*.class
        return resourcePatternResolver.getResources(packagePath);
    }

    private String packagePathParse(String packagePath) {
        packagePath = packagePath.replace(".","/");
        if (!packagePath.startsWith(ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX)) {
            // 不是以classpath开头
            packagePath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX + packagePath;
        }
        if (!packagePath.endsWith(DEFAULT_RESOURCE_PATTERN)) {
            packagePath += DEFAULT_RESOURCE_PATTERN;
        }
        return packagePath;
    }

    public List<String> getPackagePathClassNames(String packagePath) throws IOException {
        List<String> classNames = new ArrayList<>();
        Resource[] packagePathResources = this.getPackagePathResources(packagePath);
        CachingMetadataReaderFactory cachingMetadataReaderFactory = new CachingMetadataReaderFactory(resourceLoader);
        for (Resource resource : packagePathResources) {
            MetadataReader metadataReader = cachingMetadataReaderFactory.getMetadataReader(resource);
            classNames.add(metadataReader.getClassMetadata().getClassName());
        }
        return classNames;
    }

    public Set<BeanDefinition> getPackagePathBeanDefinitions(String packagePath) {
        packagePath = packagePath.replace(".","/");
        return provider.findCandidateComponents(packagePath);
    }

}



解析每一个resource,429行,通过CachingMetadataReaderFactory将resource构建成MetadataReader
430行isCandidateComponent来判断MetadataReader是否包含@Component注解
在这里插入图片描述
这里进行判断是否有@Component
在这里插入图片描述

如果包含,将metadataReader构建成beanDefinition,加入candidates。
注意这里只要有@Component注解就会加入到集合,并没有处理bean上面的Condition相关注解
在这里插入图片描述
上面的ignoreModel是加了@ConditionalOnBean(Test.class)。Test只是一个普通类

package org.hopehomi.boot.config;

import org.hopehomi.boot.controller.Test;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.stereotype.Component;

/**
 * @author Ledison
 * @date 2023/3/16
 */
@ConditionalOnBean(Test.class)
@Component
public class IgoreModel {

}

package org.hopehomi.boot.controller;

import lombok.Data;

/**
 * @author Ledison
 * @date 2023/3/16
 */
@Data
public class Test  {
    private String name = "zhangsan";
}

findCandidateComponents方法执行完后,回到ClassPathBeanDefinitionScanner第277行
将返回的Set candidates(@Component的Bean)构造成BeanDefinitionHolder
并在292行,将每个BeanDefinition加入到beanFactory的beanDefinitionMap中
在这里插入图片描述
添加到beanDefinitionMap的过程略,最终beanFactory的beanDefinitionMap结果如下
注意这里只是把beanDefinition放入了beanDefinitionMap,没有对bean进行任何初始化操作

在这里插入图片描述
以上是ConfigurationClassParser-doProcessConfigurationClass-295行的逻辑。通过启动类上ComponentScan注解,加载了包下面符合要求的@Component并构建成BeanDefinitionHolder。
小提一点:springboot是通过扫描来加载beanDefinition,而springXml是通过解析XML文件来加载beanDefinition
从298行开始,会开始递归这些BeanDefinitionHolder,让每一个BeanDefinitionHolder都走一遍刚才的加载流程
在这里插入图片描述
接下来ConfigurationClassParser-doProcessConfigurationClass-311行。
processImports(configClass, sourceClass, getImports(sourceClass), filter, true);
先看getImports方法
在这里插入图片描述
进入collectImports(sourceClass, imports, visited);
这里会递归,直到找到@Import注解。比如@SpringBootApplication 上的 @EnableAutoConfiguration上的@Import(AutoConfigurationImportSelector.class)
在这里插入图片描述
这里找到了@HopeSpringBootApplication上有@Import注解。引入了一个我定义的环境配置Selector

package org.hopehomi.core.launch.props;

import org.hopehomi.core.launch.selector.EnvironmentConfigurationSelector;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Import;
import org.springframework.core.annotation.AliasFor;

import java.lang.annotation.*;

/**
 * @author Ledison
 * @date 2023/3/16
 */

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@SpringBootApplication
@Import(EnvironmentConfigurationSelector.class)
public @interface HopeSpringBootApplication {

    @AliasFor(
            annotation = SpringBootApplication.class,
            attribute = "scanBasePackages"
    )
    String[] scanBasePackages() default {};
}

package org.hopehomi.core.launch.selector;

import org.springframework.context.annotation.ImportSelector;
import org.springframework.core.type.AnnotationMetadata;

/**
 * 环境基础配置
 *
 * @author Ledison
 * @date 2023/3/16
 */
public class EnvironmentConfigurationSelector implements ImportSelector {

    @Override
    public String[] selectImports(AnnotationMetadata importingClassMetadata) {
        return new String[]{
                "org.hopehomi.core.database.config.DruidConfiguration"
        };
    }
}

进入ConfigurationClassParser-collectImports-549行,sourceClass.getAnnotationAttributes(Import.class.getName(), “value”)
在这里插入图片描述
进入getAnnotationAttributes,第1068行,这里会获取到@Import的Value值,也就是@Import需要引入的类名
在这里插入图片描述
第1071行,执行getRelated方法,将引入的类名构造成SourceClass,并加入到集合返回
在这里插入图片描述
回到collectImports方法,第549行。添加到所有imports引用类的集合中
在这里插入图片描述
collectImports方法结束并返回,回到ConfigurationClassParser-getImports-522行。
以上代码总结为:获取从启动类开始,一直递归找到@Import的引入类,并放在集合返回,所有结果如下
imports表示满足@Import条件的,visited表示递归过的注解类
这里找到了 org.springframework.boot.autoconfigure.AutoConfigurationImportSelector(自动装配核心Selector),以及我们自定义的org.hopehomi.core.launch.selector.EnvironmentConfigurationSelector环境配置Selector
在这里插入图片描述
getImports方法结束,回到ConfigurationClassParser第311行,执行processImports方法

Process any @Import annotations

在这里插入图片描述
processImports方法,遍历所有importCandidates(SourceClass集合),判断每个SourceClass是否实现ImportSelector
如果实现了,会通过构造器生成实例,并判断Selector类是否实现了aware方法,将environment、beanFactory等变量设置到实例中
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
如果Selector实现了DeferredImportSelector(延时引入Selector),AutoConfigurationImportSelector实现了。进入578 行逻辑,将Selector放入延时引入的集合中
在这里插入图片描述
在这里插入图片描述

而如果Selector未实现DeferredImportSelector,比如我们自定义的Selector,进入581行逻辑
在这里插入图片描述
第582行,会通过默认的三个Condition(OnClass、OnWeb、OnBean,更详细的在后面还会说明)来判断是否需要过滤掉这个引入的Class,如果不需要过滤,继续将这些class会通过递归,也执行刚才的processImports逻辑
在这里插入图片描述
如果没有实现ImportSelector或者ImportBeanDefinitionRegistrar,会执行第600行逻辑,再执行processConfigurationClass,也是通过递归最终把@Component类,放入ConfigurationClassParser的configurationClasses变量
在这里插入图片描述
以上是通过@Import来加载配置类的逻辑
第ConfigurationClassParser-314行,通过@ImportResource来加载配置类
第326行,通过方法上的@Bean来加载配置类

doProcessConfigurationClass方法结束
在这里插入图片描述
结束方法后,来到ConfigurationClassParser-parse-193行。
这里开始处理延时引入的Selector(AutoConfigurationImportSelector)
在这里插入图片描述
进入process方法,创建DeferredImportSelectorGroupingHandler来处理每一个DeferredImportSelectorHolder
第780行开始执行DeferredImportSelectorHolder的
在这里插入图片描述
遍历DeferredImportSelectorGrouping,调用grouping.getImports()方法
在这里插入图片描述
getImports方法的第879行,进入this.group.process(这里的group是的AutoConfigurationImportSelector内部静态类AutoConfigurationGroup)
在这里插入图片描述
AutoConfigurationGroup-process-434行,准备开始通过Spring Spi读取自动装载类。
440行,进入getAutoConfigurationEntry方法
在这里插入图片描述
getAutoConfigurationEntry方法第125行getCandidateConfigurations
进入
进入getCandidateConfigurations方法,开始装载配置类
AutoConfigurationImportSelector的第182行,通过SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(), getBeanClassLoader())) 来装载配置类
在这里插入图片描述
getSpringFactoriesLoaderFactoryClass()方法返回的默认@EnableAutoConfiguration

在这里插入图片描述
getBeanClassLoader()方法返回类加载器(这里是appClassLoader)
在这里插入图片描述
进入SpringFactoriesLoader.loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader)
这里factoryType是EnableAutoConfiguration.class,classLoader是appClassLoader
表示加载spring.factories下,key为factoryType类型的value值
在这里插入图片描述
这里在applicationContext初始化的时候已经加载过一次SPI,所以SpringFactoriesLoader的cache变量是有值的。再根据factoryType进行过滤,返回EnableAutoConfiguration对应的value
在这里插入图片描述
AutoConfigurationImportSelector-getCandidateConfigurations-184行
ImportCandidates.load方法,用来加载META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports 文件下的类
这个和java的SPI很类似,可以从下图看到初始化定义了很多类,这些类基本都是配置在org.springframework.boot:spring-boot-autoconfigure项目下

在这里插入图片描述org.springframework.boot:spring-boot-autoconfigure下的org.springframework.boot.autoconfigure.AutoConfiguration.imports配置文件
在这里插入图片描述
ImportCandidates.load方法结束,然后把刚才加载的类和上面通过spring.factories加载的EnableAutoConfiguration实现类,合并成集合后返回。getCandidateConfigurations方法结束
在这里插入图片描述
继续回到AutoConfigurationImportSelector第130行,过滤加上Condition相关的注解类,这里的Condition默认有三个(OnBeanCondition、OnClassCondition、OnWebApplicationCondition),依然是配置在spring.factories里面
在这里插入图片描述
在这里插入图片描述
getConfigurationClassFilter().filter(configurations);
getConfigurationClassFilter()返回ConfigurationClassFilter对象,他是AutoConfigurationImportSelector的内部类
进入filter方法,依次执行三个默认Condition类的match方法,match是三个Condition的抽象父类FilteringSpringBootCondition的方法
在这里插入图片描述
通过模板模式,调用Condition的实现类getOutcomes方法
在这里插入图片描述
我这里就以OnBeanCondition举例,因为我的自定义配置类有这个注解,且@ConditionalOnBean(Test.class) 这个Test并不会被加载成bean。
在这里插入图片描述
但是这里依然没有把我自定义的类过滤掉???这个地方后面再回头思考,留一个疑问
在这里插入图片描述
结束*grouping.getImports()*方法,返回Iterable<Group.Entry>在这里插入图片描述
在这里插入图片描述

遍历所有Entry(获取到的spring.factories加载的EnableAutoConfiguration实现类自动装配类、org.springframework.boot.autoconfigure.AutoConfiguration.imports定义的类),统称为 配置文件扫描自动配置类
到812行,再次执行processImports方法,这里第三个参数Collection importCandidates。数据来自Collections.singleton(asSourceClass(entry.getImportClassName(), exclusionFilter))。
继续将每一个配置文件扫描自动配置类通过processImports来判断是否实现ImportSelector和ImportBeanDefinitionRegistrar类

回忆一下processImports的逻辑,如果实现了ImportSelector切继承DeferredImportSelector类,加入延时Selector;如果没有实现DeferredImportSelector,立即触发selectImports方法
注意区分这里调用processImports和之前递归调用。之前是通过@ComponentScan,扫描包下面的类,依次调用processImports方法。
这里是通过扫描 配置文件扫描自动配置类,来处理processImports逻辑。

在这里插入图片描述
回看process方法,其实方法已经结束,而且parse()方法也已经结束,在finally里把延时Selector集合清空。

总结一下parse()方法,分为两部分,两部分的执行目的就是获取配置类,放在ConfigurationClassParser的configurationClasses中。
第一部分:通过从启动类的@ComponentScan开始,找到符合@Component注解的类,并且在@ComponentScan之前,处理了内部类@Component、@PropertySources自定义配置加载的逻辑。递归判断@Component对象上是否包含了@Import注解,如果包含了判断引用的类是否实现ImportSelector:如果实现ImportSelector且继承自DeferredImportSelector,那么放入延时Selector继承,在后面第二部分进行处理;如果实现ImportSelector但是没有继承DeferredImportSelector,会立即执行引用Selector的selectImports方法。当类没有继承自ImportSelector或者ImportBeanDefinitionRegistrar,会作为普通配置类加入到configurationClasses集合中。这段逻辑在@ComponentScan是递归处理的
第二部分:process()方法处理第一部分获取的延时Selector集合的逻辑,主要是处理核心AutoConfigurationImportSelector,在这里会获取从spring.factories加载的EnableAutoConfiguration实现类自动装配类、org.springframework.boot.autoconfigure.AutoConfiguration.imports定义的类。然后遍历这些类,执行第一部分关于是否实现ImportSelector的逻辑。最终将这些配置放到configurationClasses集合中。

parse()方法,核心字段configurationClasses
在这里插入图片描述
可以看到configurationClasses已经缓存了很多配置类
在这里插入图片描述
parse()方法结束,回到ConfigurationClassPostProcessor343行,this.reader.loadBeanDefinitions(configClasses);
在这里开始过滤@Condition相关逻辑,并不是在之前进行判断,解决了疑问
在这里插入图片描述
从beanFactory的beanDefinitionMap去掉该类,loadBeanDefinitionsForConfigurationClass方法第143行
在这里插入图片描述
loadBeanDefinitionsForConfigurationClass第157行,在这里会调用实现了ImportBeanDefinitionRegistrar的registerBeanDefinitions方法

结束loadBeanDefinitions方法,该方法主要处理Condition相关的注解
至此,invokeBeanDefinitionRegistryPostProcessors方法也基本结束,但它只是refresh方法中invokeBeanFactoryPostProcessors(beanFactory后置处理)的一部分。
通过invokeBeanFactoryPostProcessors方法执行(ConfigurationClassPostProcessor的postProcessBeanDefinitionRegistry方法)。让beanFactory的beanDefinitionMap、beanDefinitionNames正确赋值

回到PostProcessorRegistrationDelegate-116行,从bdMap中获取实现了BeanDefinitionRegistryPostProcessor的类,在142行,会调用postProcessBeanDefinitionRegistry方法。这里的依然通过调用invokeBeanDefinitionRegistryPostProcessors来执行,和前面执行自动装配逻辑调用方法一样,只是前面通过beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false)获取的实现类只有ConfigurationClassPostProcessor。通过自动装配处理后,在后面再次调用beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false)时,可以获取到我们自定义的实现类。
在这里插入图片描述142行进入invokeBeanDefinitionRegistryPostProcessors。调用自定义类的postProcessBeanDefinitionRegistry

在这里插入图片描述
在147行,执行BeanFactoryPostProcessor接口的postProcessBeanFactory的回调
在这里插入图片描述
因为BeanDefinitionRegistryPostProcessor实现了BeanFactoryPostProcessor。所以这里的自定义类也会进行postProcessBeanDefinitionRegistry回调
在这里插入图片描述

invokeBeanFactoryPostProcessors方法总结

执行BeanDefinitionRegistryPostProcessor回调

  1. 执行默认传入的三个BeanDefinitionRegistryPostProcessor的回调postProcessBeanDefinitionRegistry

Invoke BeanDefinitionRegistryPostProcessors first, if any.

在这里插入图片描述

  1. 执行beanFactory中前面设置的bdMap中类型为BeanDefinitionRegistryPostProcessor的回调,且bean实现了PriorityOrdered接口
    这一步是自动装配核心,由ConfigurationClassPostProcessor执行
    在这里插入图片描述

First, invoke the BeanDefinitionRegistryPostProcessors that implement PriorityOrdered.

在beanFactory.getBean(beanName, xxx.class)。会通过beanFactory查询singletonObjects中是否能获取到对象实例,如果获取不到,且在mergedBeanDefinitions存在该key,会创建对象实例,放到singletonObjects中,这一块逻辑在以后章节再分析
在这里插入图片描述

  1. 通过第二步自动装载后,再次执行bdMap中类型为BeanDefinitionRegistryPostProcessor的回调,且bean实现了Ordered接口

Next, invoke the BeanDefinitionRegistryPostProcessors that implement Ordered.

在这里插入图片描述
在这里插入图片描述

  1. 执行剩余未执行的BeanDefinitionRegistryPostProcessor的回调

Finally, invoke all other BeanDefinitionRegistryPostProcessors until no further ones appear.

在这里插入图片描述

  1. 执行实现了BeanDefinitionRegistryPostProcessor的父类BeanFactoryPostProcessor回调方法postProcessBeanFactory。如果bean只实现了BeanFactoryPostProcessor,不会在这里执行回调

Now, invoke the postProcessBeanFactory callback of all processors handled so far.

这里ConfigurationClassPostProcessor也是实现了BeanDefinitionRegistryPostProcessor,他是动态代理处理类,这个在(下)文章中说明
在这里插入图片描述
在这里插入图片描述

执行BeanFactoryPostProcessors回调

  1. 执行BeanFactoryPostProcessors的回调,且实现了PriorityOrdered

First, invoke the BeanFactoryPostProcessors that implement PriorityOrdered.
在这里插入图片描述

  1. 执行BeanFactoryPostProcessors的回调,且实现了Ordered

Next, invoke the BeanFactoryPostProcessors that implement Ordered.
在这里插入图片描述

  1. 执行剩余的BeanFactoryPostProcessors的回调

Finally, invoke all other BeanFactoryPostProcessors.

在这里插入图片描述

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
springboot uview-ui商城源码是一个使用了Spring Boot和uView-UI开发的电商平台的源代码。它提供了一个完整的电商平台的基础功能和界面设计,方便开发者进行二次开发和定制。 该源码采用了Spring Boot框架作为后端的开发框架,Spring Boot是一个快速开发Java应用程序的框架,它可以帮助开发者快速搭建基于Java的Web应用程序。而uView-UI是一个基于Vue.js的UI组件库,它提供了丰富的界面组件和样式,帮助开发者快速构建漂亮的前端界面。 该商城源码包含了用户管理、商品管理、订单管理等基本功能模块。用户管理模块可以实现用户注册、登录、个人信息修改等操作;商品管理模块可以实现商品的添加、编辑、删除等操作;订单管理模块可以实现订单的查询、支付、取消等操作。 此外,该商城源码还包含了购物车、搜索功能、商品详情页等重要功能。购物车功能可以实现商品的添加、删除、数量修改等操作;搜索功能可以实现关键词的检索,并显示与关键词相关的商品列表;商品详情页可以显示商品的详细信息,包括图片、价格、库存等。 开发者可以根据自己的需求进行二次开发和定制,例如可以添加更多的功能模块、修改样式和布局、集成支付接口等。同时,由于该源码使用了Spring Boot和uView-UI这两个流行的框架,开发者可以借助它们的丰富生态系统和社区支持,更高效地开发和维护电商平台。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值