SpringBoot3启动源码解析
SpringBoot源码解析
自动配置(SpringBootApplication)
自动配置是指根据我们添加的jar包依赖,会自动将一些配置类的bean注册进IOC容器,我们可以在需要的地方使用@Autowired或者@Resource等注解来使用。
那么SpringBoot是如何实现自动配置的呢,都把那些组件进行了自动配置?
首先需要从启动类说起。
被标注了SpringBootApplication的类为核心启动类,此注解是一个组合注解,,此注解中重要的就是SpringBootConfiguration、EnableAutoConfiguration、ComponentScan
1 | //注解的适用5范围,Type表示注解可以描述在类、接口、注解或枚举中 |
SpringBootConfiguration
1 |
|
EnableAutoConfiguration
1 |
|
Spring中有很多以Enable开头的注解,其作用就是借助@Import来收集并注册特定场景相关的Bean,并加载到IOC容器中。
@EnableAutoConfiguration就是借助@Import来收集所有符合自动配置条件的bean的定义,并加载到IOC容器。
AutoConfigurationPackage
1 |
|
@AutoConfigurationPackage:自动配置包,也是一个组合注解,其中最重要的注解是@Import(AutoConfigurationPackages.Registrar.class),他是Spring框架的底层注解,他的作用就是给容器中导入某个组件类,例如@Import(AutoConfigurationPackages.Registrar.class),它是将Registrar这个组件类导入到容器中,可查看Registrar中的registerBeanDefinitions方法。
1 | //AutoConfigurationPackages.Registrar.class,是AutoConfigurationPackages中的一个静态类 |
AutoConfigurationPaackages.Registrar这个类就干一个事,注册一个bean,这个bean就是org.springframework.boot.autoconfigure.AutoConfigurationPackages.BasePackages,它只有一个参数,这个参数是试用了@AutoConfigurationPackage这个注解的类所在的包路径,保存自动配置类以供之后的使用。
bean注册方法包含两个参数,其中metadata是注解的元数据信息,registry为bean定义的注册中心

@Import(AutoConfigurationImportSelector.class)
借助@Import,将AutoConfigurationSelector注入IOC容器中,AutoConfigurationSelector可以帮助SpringBoot将所有符合条件的@Configuration配置都加载到当前SpringBoot创建并使用的IOC容器(ApplicationConttext)中

从类继承上可以看出该类继承了BeanClassLoaderAware,ResourceLoaderAware, BeanFactoryAware, EnvironmentAware几个Aware接口,实现Aware接口,就会执行相应的回调,拿到对应的Sspring组件,然后赋值给此类中的对应属性;
此外还实现了DeferredImportSelector,是ImportSelectot(spring中用于导入外部配置的核心接口),
1 | public class AutoConfigurationImportSelector implements DeferredImportSelector, BeanClassLoaderAware, |
确定自动配置实现逻辑的入口方法:跟自动配置相关的入口方法在DeferredImportSelectorGrouping类中的getImports方法处,因此我们从DeferredImportSelectorGrouping类的getImports方法开始分析SpringBoot的自动配置就好(后续有调用入口说明)
DeferredImportSelectorGrouping是ConfigurationClassParser的一个静态内部类
1 | class ConfigurationClassParser { |
实现逻辑在AutoConfigurationImportSelector中的AutoConfigurationGroup类
1 | public class AutoConfigurationImportSelector implements DeferredImportSelector, BeanClassLoaderAware, |
Spring条件注解
| 类型 | 说明 |
|---|---|
| ConditionalOnBean | 仅仅在当前上下文中存在某个对象时,才会实例化一个Bean |
| ConditionalOnClass | 某个class位于类路径上,才会实例化一个Bean |
| ConditionalOnExpression | 当表达式为true的时候,才会实例化一个Bean。 |
| ConditionalOnMissingBean | 仅仅在当前上下文中不存在某个对象时,才会实例化一个Bean。 |
| ConditionalOnMissingClass | 某个class类路径上不存在的时候,才会实例化一个Bean。 |
| ConditionalOnNotWebApplication | 不是web应用,才会实例化一个Bean。 |
| ConditionalOnBean | 当容器中有指定Bean的条件下进行实例化。 |
| ConditionalOnMissingBean | 当容器里没有指定Bean的条件下进行实例化。 |
| ConditionalOnClass | 当classpath类路径下有指定类的条件下进行实例化。 |
| ConditionalOnMissingClass | 当类路径下没有指定类的条件下进行实例化。 |
| ConditionalOnWebApplication | 当项目是一个Web项目时进行实例化。 |
| ConditionalOnNotWebApplication | 当项目不是一个Web项目时进行实例化。 |
| ConditionalOnProperty | 当指定的属性有指定的值时进行实例化。 |
| ConditionalOnExpression | 基于SpEL表达式的条件判断。 |
| ConditionalOnJava | 当JVM版本为指定的版本范围时触发实例化。 |
| ConditionalOnResource | 当类路径下有指定的资源时触发实例化。 |
| ConditionalOnJndi | 在JNDI存在的条件下触发实例化。 |
| ConditionalOnSingleCandidate | 当指定的Bean在容器中只有一个,或者有多个但是指定了首选的Bean时触发实例化。 |
@ComponentScan
ComponentScan的使用
主要是从定义的路径扫描中,找出标识了需要装配的类自动装配到spring的bean容器中。
常用属性如下
- basePackages、value:指定扫描路径,如果为空则以@ComponentScan注解的类所在的包为基本扫描路径
- basePackageClasses:指定具体扫描的类
- includeFilters:指定满足Filter条件的类
- excludeFilters:指定排除Filter条件的类
includeFilters和excludeFilters的FilterType可选:ANNOTATION=注解类型(默认)、ASIGNABLE_TYPE(指定固定类)、ASSPECTTJ(ASPECTJ类型)、REGEX(正则表表达式)、CUSTOM(自定义类型),自定义的Filter需要实现TypeFilter接口
@ComponentScan的配置如下
1 |
借助excludeFilters将TypeExcludeFilter及FilteType这两个二类进行排除
当前@ComponentScan注解没有标注basePackages及value,所以扫描路径默认为@ComponentScan注解的类所在包作为基本的扫描路径(也就是标注了@SpringBootApplication注解的项目启动类所在的路径)
抛出疑问:@EnableAutoConfiguration注解通过@Import注解进行自动配置固定的bean
@Componen注解自动进行注解扫描
1 | 那么真正根据包扫描,把组件类生成实例对象存在IOC容器中,又是如何完成的? |
源码分析-Run方法执行流程
SpringBootApplication初始化过程
1 | public class SpringApplication { |
getSpringFactoriesInstances(ApplicationContextInitializer.class)

getSpringFactoriesInstances(ApplicationListener.class)

run方执行
1 | public class SpringApplication { |
获取启动监听器
1 | public class SpringApplication { |
构建应用上下文环境
1 | public class SpringApplication { |
listeners.environmentPrepared()用于发布环境准备完成通知,然后由获取到的ApplicationListener执行相应逻辑
其中有一个EnvironmentPostProcessorApplicationListener用于配置文件的加载。
1 | public class EnvironmentPostProcessorApplicationListener implements SmartApplicationListener, Ordered { |
获取到的后置处理器有

其中ConfigDataEnvironmentPostProcessor用于配置文件的激活处理
1 | public class ConfigDataEnvironmentPostProcessor implements EnvironmentPostProcessor, Ordered { |
— 旧版本使用ConfigFileApplicationListener加载配置文件
监听器ConfigFileApplicationListener,加载项目配置文件的监听器
1 | class SpringApplicationRunListeners { |
1 | class EventPublishingRunListener implements SpringApplicationRunListener, Ordered { |
初始化应用上下文
1 |
|
1 | // ApplicationContextFactory |
刷新应用上下文的准备阶段
1 | public class SpringApplication { |
刷新应用上下文
1 | public abstract class AbstractApplicationContext extends DefaultResourceLoader |
invokeBeanFactoryPostProcessors(beanFactory) (重点)
Ioc容器的初始化过程包含三个步骤,在invokeBeanFactoryPostProcessors()方法中完成了Ioc容器初始化过程的三个步骤
Reosurce定位
在SpringBoot中,我们都知道他的包扫描是从主类所在的包开始扫描的,preareContext()方法中,回先将主类解析成BeanDefinition,然后在refressh()方法的invokeBeanFactoryPostProcessors()方法中解析主类的BeanDefinition获取basePackage的路径。这样就完成了定位的过程。其次SpringBoot的各种starter是通过SPI扩展机制实现的自动装配,SpringBoot的自动装配同样也是在invokeBeanFactoryPostProcessors()方法中实现的。还有一种情况,在SpringBoot中有很多@EnableXXX的注解,细心点进去看的应该就知道其底层就是@Import注解,在啊invokeBeanFactoryPostProcessors()方法中实现了对该注解指定的配置类的定位加载。
常规的在SpringBoot中有三种定位,第一种是主类所在的包,第二种是SPI机制扩展实现的自动装配(比如各种starter),第三种就是@Import注解指定的类(对于非常规的)
BeanDefinition载入
在第一步中说了的暗中Resource的定位情况,定位后紧接着就是BeanDefinition的分别载入。所谓的载入就是通过上面啊的定位得到的basePackage,SpringBoot会将该路径拼接成:classpath:net/oiyou/**/.class这样的形式,然后一个叫做xPathMatchingResourcePatternResolver的类会将该路径下的所有的.class文件啊都加载进来,然后遍历是不是有@Companent注解,如果有就是我们吖装载的BeanDefinitio。大致过程就是这样的了。
1
2TIPS:
@Configuration @Controller @Service等注解底层都是@Companent注解,只不过包装了一层罢了注册BeanDefinition
这个过程通过调用上下文的BeanDefinitionRegister接口的实现来完成。这个注册过程把载入过程中解析得到的BeanDefinition向Ioc容器中进行注册。通过上下文的分析,我们可以看到,在Ioc容器中将BeanDefinition注入到ConcurrentHashMap中,Ioc容器就是十四通过这个HashMap来持有这些BeanDefinition数据的。比如DefaultListableBeanFactory中的beanDefinitionMap属性。
1 | public abstract class AbstractApplicationContext extends DefaultResourceLoader |
调用PostProcessorRegistrationDelegate的invokeBeanFactoryPostProcessors方法
1 | final class PostProcessorRegistrationDelegate { |
1 | public class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPostProcessor, |
1 | public ConfigurationClassParser(MetadataReaderFactory metadataReaderFactory, |
刷新应用上下文的扩展接口
1 | protected void afterRefresh(ConfigurableApplicationContext context, ApplicationArguments args) { |
后续计划
- BootstrapRegistryInitializer,ApplicationContextInitializer,ApplicationListener什么作用
- DefaultBootstrapContext作用?
- SpringApplicationRunListener作用
- SpringApplicationHook作用
