一,Springboot 启动整体流程
Spring Boot 能够让你非常容易的创建一个基于 spring framework 的应用,以最小的代价开始一个项目。
Springboot 的启动,主要创建了配置环境、事件监听、应用上下文,并基于以上条件,在容器中开始实例化、初始化我们需要的 Bean。主要流程包括两步骤,创建并初始化 SpringApplication 和执行 run 方法。
@SpringBootApplication
public class ApiApplication {
public static void main(String[] args) {
//启动类静态run方法
SpringApplication.run(ApiApplication.class, args);
}
}
1.创建并初始化 SpringApplication
- SpringApplication 对象在初始化时,从类路径中推断并设置应用类型。应用类型有三种:非 web 应用,基于servlet 的 web 应用和基于 REACTIVE 的 web 应用;
- 从 SpringFactories 文件中找到配置的事件监听器,并保存起来;
- 推断运行主类;
2.执行run方法
- 创建了应用的监听器 SpringApplicationRunListeners 并开始监听;
- 加载 SpringBoot 配置环境(ConfigurableEnvironment),如果是通过web容器发布,会加载StandardEnvironment,其最终也是继承了ConfigurableEnvironment;
- 创建run方法的返回对象:ConfigurableApplicationContext(应用配置上下文),ConfigurableApplicationContext 是 ApplicationContext 的子类,该接口的主要任务就是配置应用上下文功能。
- 回到 run 方法内,prepareContext 方法将 listeners、environment、applicationArguments、banner 等重要组件与上下文对象关联;
- 接下来的 refreshContext(context) 方法是实现自动化配置的关键,包括 spring.factories 的加载,bean 的实例化等核心工作;
- 启动监听器,通知程序运行。
二,构造方法
// SpringApplication.java
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
// 省略...
this.primarySources = new LinkedHashSet(Arrays.asList(primarySources));
// 确定application类型
this.webApplicationType = WebApplicationType.deduceFromClasspath();
// 加载初始化容器
this.setInitializers(this.getSpringFactoriesInstances(ApplicationContextInitializer.class));
// 找到配置的事件监听器,并保存起来
this.setListeners(this.getSpringFactoriesInstances(ApplicationListener.class));
// 推断运行主类
this.mainApplicationClass = this.deduceMainApplicationClass();
}
三,执行run() 方法
创建完 SpringApplication 实例之后,继续执行 run 方法,run方法的源码如下:
// org.springframework.context.ConfigurableApplicationContext
public ConfigurableApplicationContext run(String... args) {
//1.开启程序启动计时器
long startTime = System.nanoTime();
DefaultBootstrapContext bootstrapContext = createBootstrapContext();
ConfigurableApplicationContext context = null;
//2.无输入不影响工作
configureHeadlessProperty();
//3.获取监听器
SpringApplicationRunListeners listeners = getRunListeners(args);
//4.启动监听器
listeners.starting(bootstrapContext, this.mainApplicationClass);
try {
//5.设置程序启动参数
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
//6.配置环境
ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments);
//7.跳过bean检索
configureIgnoreBeanInfo(environment);
//8.打印banner
Banner printedBanner = printBanner(environment);
//9.创建应用程序上下文
context = createApplicationContext();
context.setApplicationStartup(this.applicationStartup);
// 将listeners、environment、applicationArguments、banner等重要组件与上下文关联
prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);
//10.刷新上下文,完成对 Bean 的扫描、实例化、初始化(重要)
refreshContext(context);
//11.上下文后置处理
afterRefresh(context, applicationArguments);
//12.结束计时器
Duration timeTakenToStartup = Duration.ofNanos(System.nanoTime() - startTime);
if (this.logStartupInfo) {
new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), timeTakenToStartup);
}
//13.启动监听器
listeners.started(context, timeTakenToStartup);
//14.通知程序运行
callRunners(context, applicationArguments);
}
catch (Throwable ex) {
handleRunFailure(context, ex, listeners);
throw new IllegalStateException(ex);
}
try {
Duration timeTakenToReady = Duration.ofNanos(System.nanoTime() - startTime);
listeners.ready(context, timeTakenToReady);
}
catch (Throwable ex) {
handleRunFailure(context, ex, null);
throw new IllegalStateException(ex);
}
return context;
}
四,refresh() 源码分析
#refresh()
方法,是定义在 ConfigurableApplicationContext 类中的,作用就是:刷新 Spring 的应用上下文。在这个方法中,完成对 Bean 的扫描、实例化、初始化。
// org.springframework.context.support.AbstractApplicationContext#refresh
@Override
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// 1 准备刷新上下文环境,对系统的环境变量或者系统属性进行准备和校验
prepareRefresh();
// 2 创建并初始化 BeanFactory
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// 3 填充BeanFactory功能
prepareBeanFactory(beanFactory);
try {
// 4 提供子类覆盖的额外处理,即子类处理自定义的BeanFactoryPostProcess
postProcessBeanFactory(beanFactory);
// 5 激活各种BeanFactory处理器,找到并加载BeanFactoryPostProcessor实现类
// 加载BeanDefinition放入到BeanDefinitionMap中
invokeBeanFactoryPostProcessors(beanFactory);
// 6 注册拦截Bean创建的Bean处理器,即注册 BeanPostProcessor
registerBeanPostProcessors(beanFactory);
// 7 初始化上下文中的资源文件,如国际化文件的处理等
initMessageSource();
// 8 初始化上下文事件广播器
initApplicationEventMulticaster();
// 9 给子类扩展初始化其他Bean,预留给 AbstractApplicationContext 的子类用于
// 初始化其他特殊的 bean,该方法需要在所有单例 bean 初始化之前调用。
onRefresh();
// 10 在所有bean中查找listener bean,然后注册到广播器中
registerListeners();
// 11 实例化、初始化剩下的单例Bean(非延迟加载的)
finishBeanFactoryInitialization(beanFactory);
// 12 完成刷新过程,通知生命周期处理器lifecycleProcessor刷新过程
// 主要调用 LifecycleProcessor#onRefresh() ,并发布事件ContextRefreshedEvent
finishRefresh();
} catch (BeansException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - " +
"cancelling refresh attempt: " + ex);
}
// 13 销毁已经创建的Bean
destroyBeans();
// 14 重置容器激活标签
cancelRefresh(ex);
//抛出异常
throw ex;
} finally {
// Reset common introspection caches in Spring's core, since we
// might not ever need metadata for singleton beans anymore...
resetCommonCaches();
}
}
}
第5步分析
invokeBeanFactoryPostProcessors(beanFactory) 方法,激活各种 BeanFactory 处理器,会去调用ConfigurationClassPostProcessor 这个bean工厂的后置处理器完成扫描,将加载的 BeanDefinition 放入BeanDefinitionMap 中。
执行完此方法后,可以看到已将扫描的BeanDefinition放入到了BeanDefinitionMap中,org.springframework.context.support.PostProcessorRegistrationDelegate#invokeBeanDefinitionRegistryPostProcessors
第11步分析
finishBeanFactoryInitialization(beanFactory) 方法,实例化、初始化剩下的单例Bean(非延迟加载的)
// org.springframework.context.support.AbstractApplicationContext#finishBeanFactoryInitialization
protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
// 省略...
// 开始实例化
beanFactory.preInstantiateSingletons();
}
preInstantiateSingletons() 方法中,调用 getBean(beanName) 方法区获取 bean,getbean流程可以参考以下文章:Spring 如何处理循环依赖文章:创建Bean完整流程,完成对 Bean 的实例化,属性填充(在这里处理循环依赖问题)以及初始化。
评论区