SpringBoot源码解析
1.启动的过程:
- 首先在main函数中启动当前应用程序(SpringApplication启动)
- 创建SpringApplication对象(new SpringApplication()).在对象的构造方法中进行参数的初始化工作,最主要的是判断当前应用程序的类型以及初始化器和监听器,在此过程中会加载整个应用程序中的spring.factories文件,将文件的内容放在缓存对象中,方便后续获取,具体步骤如下:
- 配置resourceloader
- 判断当前应用程序的类型
- 获取初始化器的实例对象
- 获取监听器的实例对象
- 找到当前应用程序的主类,开始执行
- SpringApplication对象创建完成之后开始执行run()方法,来完成整个启动过程.而run方法中主要的步骤如下:
- 设置启动时间
- 设置上下文
- 设置异常报告器
- 创建监听器并从中获取符合监听事件的几个监听器
- 配置命令行参数
- 准备应用程序运行的环境
- 接着是核心的上下文部分,分为prepareContext()上下文的前置处理,refreshContext()核心方法,就是spring中的refresh()方法,其中的beanFactoryPostProcessor()完成自动装配的核心,afterRefresh()上下文后置结束处理
- 之后就是发布应用上下文启动,执行runner()运行器
- 发布应用上下文就绪并返回
- SpringApplication启动结束
2.具体的run()方法源码如下:
public ConfigurableApplicationContext run(String... args) {
//设置启动时间
long startTime = System.nanoTime();
//设置上下文
DefaultBootstrapContext bootstrapContext = this.createBootstrapContext();
ConfigurableApplicationContext context = null;
this.configureHeadlessProperty();
//创建监听器并从中获取符合监听事件的几个监听器
SpringApplicationRunListeners listeners = this.getRunListeners(args);
listeners.starting(bootstrapContext, this.mainApplicationClass);
try {
//配置命令行参数
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
//准备应用程序运行的环境
ConfigurableEnvironment environment = this.prepareEnvironment(listeners, bootstrapContext, applicationArguments);
this.configureIgnoreBeanInfo(environment);
//打印banner(也就是那个p用没有的图标)
Banner printedBanner = this.printBanner(environment);
context = this.createApplicationContext();
context.setApplicationStartup(this.applicationStartup);
//prepareContext和refreshContext是自动装配的核心方法 而且这个refreshContext方法就是spring中的refresh()方法 使用的就是里面的beanFactoryPostProcessor()来实现的自动装配
this.prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);
this.refreshContext(context);
this.afterRefresh(context, applicationArguments);
Duration timeTakenToStartup = Duration.ofNanos(System.nanoTime() - startTime);
//发布应用上下文启动,执行runner()运行器
if (this.logStartupInfo) {
(new StartupInfoLogger(this.mainApplicationClass)).logStarted(this.getApplicationLog(), timeTakenToStartup);
}
listeners.started(context, timeTakenToStartup);
this.callRunners(context, applicationArguments);
} catch (Throwable var12) {
this.handleRunFailure(context, var12, listeners);
throw new IllegalStateException(var12);
}
//发布应用上下文就绪并返回
try {
Duration timeTakenToReady = Duration.ofNanos(System.nanoTime() - startTime);
listeners.ready(context, timeTakenToReady);
return context;
} catch (Throwable var11) {
this.handleRunFailure(context, var11, (SpringApplicationRunListeners)null);
throw new IllegalStateException(var11);
}
}
3.自动装配的原理
自动装配的实现就是为了从spring.factories文件中获取到对应的bean对象,并且由spring容器帮我们进行管理.
- 当启动SpringBoot应用程序的时候会先创建SpringApplication对象,在对象的构造方法中进行参数的初始化工作,最主要的是判断当前应用程序的类型以及初始化器和监听器,在此过程中会加载整个应用程序中的spring.factories文件,将文件的内容放在缓存对象中,方便后续获取
- SpringBoot对象创建完成之后,开始执行run()方法来完成整个启动过程.启动过程中主要包括的两个方法:prepareContext()和refreshContext()方法,在这两个关键的步骤中完成自动装配的核心功能
- 在prepareContext()方法中主要完成的是对上下文对象的初始化操作,包括属性值的设置,在整个过程中最重要的方法是load(),主要完成将当前启动类作为一个beanDefinition注册到registry(注册表)中,方便后续进行BeanFactoryPostProcesser调用执行的时候,找到对应的主类,来完成对@SpringBootApplication,@EnableAutoConfiguration等注解的解析工作(注意:要完成这些注解的解析工作,必须要获取到启动类)
- 在refreshContext()方法中,会调用spring中的refresh()方法(refresh()方法一共有13个非常关键的方法来完成整个spring应用程序的启动),在自动装配中会调用invokeBeanFactoryPostProcessor()方法,在此方法中主要是对ConfigurationClassPathPostProcessor类的处理(它是BeanFactoryPostProcessor的子类,也是BeanDefinitionReaderPostProcessor的子类).在调用的时候会先调用BeanDefinitionReaderPostProcessor中的postProcessorBeanDefinitionRegistry方法,然后调用PostProcessBeanFactory()方法,在执行postProcessorBeanDefinitionRegistry方法的时候会解析处理各种注解,最主要的是对@Import注解的解析
- 在解析@Impo注解的时候,会有一个getInstance()方法,从主类中递归解析注解,把所有@Import的注解都解析到,然后在processImport()方法中对Import的类进行分类,此处主要识别的是@Import(AutoConfigurationImportSelect.class)中的AutoConfigurationImportSelect,在后续的过程中调用deferredImportSelectorHandler()中的方法来完成EnableAutoConfiguration对象的加载,之后获取到spring.factories找到大量的自动装配的类(并不是所有的类都会用到),将不适用的装配类移除,过滤掉多余的装配类(starter的作用就是确定那些配置类是需要的,哪些是不需要的)