SpringBoot 版本 2.7.1
SpringApplication在构造方法时,就会读取META-INF/spring.factories的类,缓存到SpringFactoriesLoader中(这是Spring的SPI),注意这里的缓存不仅仅只有org.springframework.boot.autoconfigure.EnableAutoConfiguration,包括文件中所有key-value
缓存是一个静态变量
SpringApplication第298行,通过SPI从META-INF/spring.factories获取org.springframework.boot.SpringApplicationRunListener的实现类并加载
通过构造器创建自定义RunListener实例
进入到自定义RunListener的构造方法
第299行,通过spring.factories获取的所有SpringApplicationRunListener的实现类,并调用start方法
SpringApplication第302行,创建spring环境配置类,默认环境变量实现类为ApplicationServletEnvironme
ApplicationServletEnvironment的抽象父类为AbstractEnvironment,他的成员变量MutablePropertySources propertySources是环境变量核心。包含了List
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环境配置类创建
创建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逻辑。
进行ApplicationContext赋值处理,SpringApplication第307行prepareContext方法
进入prepareContext方法,这里赋值了environment、添加默认类到IOC容器(beanFactory的间接父类DefaultSingletonBeanRegistry中的singletonObjects,作为一级缓存)、设置循环依赖状态、添加默认BeanFactoryPostProcessor
调用SpringApplicationRunListener的contextPrepared、contextLoaded方法
SpringApplication第308行,核心方法refreshContext(context);
调用context.refresh(),由AnnotationConfigServletWebServerApplicationContext的间接抽象父类AbstractApplicationContext来实现。
这里的实现很简单,只是返回了beanFactory对象(如果context是用spring的ClassPathXmlApplicationContext,会在这里进行beanDefinition的构建,这里不做深入区别讨论)
Prepare the bean factory for use in this context.
会默认添加一些beanPostProcess实现(比如ApplicationContextAwareProcessor,用来判断bean是否实现了各种Aware接口,如果实现了,ApplicationContextAwareProcessor会在postProcessBeforeInitialization执行回调)。
会默认注册一些单例bean到ioc容器(比如 environment、systemProperties、systemEnvironment等)。DefaultListableBeanFactory的父类DefaultSingletonBeanRegistry,里面的成员变量 Map
Allows post-processing of the bean factory in context subclasses.
由AnnotationConfigServletWebServerApplicationContext实现
super.postProcessBeanFactory(beanFactory)。会添加WebApplicationContextServletContextAwareProcessor到BeanPostProcessor
4. AbstractApplicationContext第564行,invokeBeanFactoryPostProcessors。
这个方法会执行springboot的自动装配核心逻辑
Invoke factory processors registered as beans in the context.
PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors 方法
第112行invokeBeanDefinitionRegistryPostProcessors
进入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集合只有启动类
第327行
Set 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注解的类逻辑
进入ConfigurationClassParser,可以看到这里针对类上的注解做了很多判断,是否有@Component、@PropertySource、@ComponentScan、@Import注解等
先看ConfigurationClassParser-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路径