装载: https://blog.csdn.net/Oblak_ZY/article/details/124769216
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的作用就是确定那些配置类是需要的,哪些是不需要的)