springboot启动流程,手把手打断点一步步看运行步骤
目录
一、让我们从启动类打断点一点点剖析启动过程
二、创建 SpringApplication
1.new SpringApplication
2.初始化参数
(1)获取bootstrappers:初始启动引导器
(2)获取ApplicationContextInitializer初始化器
(3)获取ApplicationListener 应用监听器
三、运行 SpringApplication
1.进入run方法
(1)创建引导上下文(Context环境)
(2)bootstrapper其实是个接口
(3)获取所有 RunListener(运行监听器)
(4)准备运行时环境
(5)创建IOC容器
(6)准备ApplicationContext IOC容器的基本信息
(7)IOC容器的经典初始化过程
(8)调用所有runners
一、让我们从启动类打断点一点点剖析启动过程
public static void main(String[] args) {SpringApplication.run(WebApplicationCxf.class, args);
}
二、创建 SpringApplication
1.new SpringApplication
// org.springframework.context.ConfigurableApplicationContext
public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {return new SpringApplication(primarySources).run(args);
}
2.初始化参数
// org.springframework.boot.SpringApplication#SpringApplication(org.springframework.core.io.ResourceLoader, java.lang.Class<?>...)
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {this.resourceLoader = resourceLoader;// 资源加载器Assert.notNull(primarySources, "PrimarySources must not be null");// 断言,判断是否有主配置类this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));// 主配置类信息保存起来(标注@SpringBootApplication的)this.webApplicationType = WebApplicationType.deduceFromClasspath();// 判断web应用的类型(判断是响应式还是原生的servlet工程)// bootstrappers:初始启动引导器(List<Bootstrapper>):去spring.factories文件中找 org.springframework.boot.Bootstrapperthis.bootstrappers = new ArrayList<>(getSpringFactoriesInstances(Bootstrapper.class));// 找 ApplicationContextInitializer初始化器;去spring.factories找 ApplicationContextInitializer// 存放在List<ApplicationContextInitializer<?>> initializers中,总共7个setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));// 找 ApplicationListener ;应用监听器。去spring.factories找 ApplicationListener// 存放在List<ApplicationListener<?>> listeners中,总共9个setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));// 决定谁是主程序,有main方法的类就是主程序this.mainApplicationClass = deduceMainApplicationClass();
}
(1)获取bootstrappers:初始启动引导器
// org.springframework.boot.SpringApplication#getSpringFactoriesInstances(java.lang.Class<T>, java.lang.Class<?>[], java.lang.Object...)
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) {ClassLoader classLoader = getClassLoader();// Use names and ensure unique to protect against duplicates// 去spring.factories文件中找 org.springframework.boot.BootstrapperSet<String> names = new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader));List<T> instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);AnnotationAwareOrderComparator.sort(instances);return instances;
}
(2)获取ApplicationContextInitializer初始化器
都是从spring.factories文件中查找 ApplicationContextInitializer,可能不仅局限于一个spring.factories文件
(3)获取ApplicationListener 应用监听器
都是从spring.factories文件中查找ApplicationListener ,可能不仅局限于一个spring.factories文件
三、运行 SpringApplication
1.进入run方法
// org.springframework.context.ConfigurableApplicationContext
public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {return new SpringApplication(primarySources).run(args);
}
// org.springframework.boot.SpringApplication#run(java.lang.String...)
public ConfigurableApplicationContext run(String... args) {// 应用停止监听器StopWatch stopWatch = new StopWatch();stopWatch.start(); // 记录应用的启动时间// 创建引导上下文(Context环境)createBootstrapContext()DefaultBootstrapContext bootstrapContext = createBootstrapContext();ConfigurableApplicationContext context = null;// 设置headless属性方法(java.awt.headless),让当前应用进入headless模式(自力更生模式,详情自行百度)configureHeadlessProperty();//获取所有 RunListener(运行监听器)【为了方便所有Listener进行事件感知】SpringApplicationRunListeners listeners = getRunListeners(args);// 遍历 SpringApplicationRunListener 调用 starting 方法,相当于通知所有对系统正在启动过程感兴趣的人,项目正在 starting。listeners.starting(bootstrapContext, this.mainApplicationClass);try {// 保存命令行参数;ApplicationArgumentsApplicationArguments applicationArguments = new DefaultApplicationArguments(args);// 准备运行时环境ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments);configureIgnoreBeanInfo(environment);// 打印bannerBanner printedBanner = printBanner(environment);// 创建IOC容器// 根据项目类型(Servlet)创建容器,当前会创建 AnnotationConfigServletWebServerApplicationContextcontext = createApplicationContext();context.setApplicationStartup(this.applicationStartup);// 准备ApplicationContext IOC容器的基本信息prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);// 刷新IOC容器,调用IOC容器的经典初始化过程,创建容器中的所有组件refreshContext(context);// 容器刷新完成后工作,方法是空的afterRefresh(context, applicationArguments);// 监控花费的时间stopWatch.stop();if (this.logStartupInfo) {new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);}// 所有监听器 调用 listeners.started(context); 通知所有的监听器 startedlisteners.started(context);// 调用所有runnerscallRunners(context, applicationArguments);}// 如果有异常,调用Listener 的 failed方法catch (Throwable ex) {handleRunFailure(context, ex, listeners);throw new IllegalStateException(ex);}try {// 调用所有监听器的 running 方法 listeners.running(context); 通知所有的监听器 runninglisteners.running(context);}// running如果有问题。继续通知 failed 。调用所有 Listener 的 failed;通知所有的监听器 failedcatch (Throwable ex) {handleRunFailure(context, ex, null);throw new IllegalStateException(ex);}return context;
}
(1)创建引导上下文(Context环境)
private DefaultBootstrapContext createBootstrapContext() {DefaultBootstrapContext bootstrapContext = new DefaultBootstrapContext(); // 创建默认的引导上下文// 获取到所有之前的 bootstrappers 挨个执行 intitialize() 来完成对引导启动器上下文环境设置this.bootstrappers.forEach((initializer) -> initializer.intitialize(bootstrapContext));return bootstrapContext;
}
(2)bootstrapper其实是个接口
public interface Bootstrapper {/*** Initialize the given {@link BootstrapRegistry} with any required registrations.* @param registry the registry to initialize*/void intitialize(BootstrapRegistry registry);
}
(3)获取所有 RunListener(运行监听器)
还是去从spring.factories文件中查找SpringApplicationRunListener。
private SpringApplicationRunListeners getRunListeners(String[] args) {Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class };return new SpringApplicationRunListeners(logger,getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args),this.applicationStartup);
}
找到一个listener:
Listener实际是个接口,有如下方法:
(4)准备运行时环境
// org.springframework.boot.SpringApplication#prepareEnvironment
private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners,DefaultBootstrapContext bootstrapContext, ApplicationArguments applicationArguments) {// Create and configure the environment// 返回或者创建基础环境信息对象。StandardServletEnvironmentConfigurableEnvironment environment = getOrCreateEnvironment();// 配置环境信息,通过命令行参数或者配置文件获取配置属性值configureEnvironment(environment, applicationArguments.getSourceArgs());// 绑定环境信息ConfigurationPropertySources.attach(environment);// 所有监听器遍历调用 listener.environmentPrepared();通知所有的监听器当前环境准备完成listeners.environmentPrepared(bootstrapContext, environment);DefaultPropertiesPropertySource.moveToEnd(environment);// 激活额外的环境configureAdditionalProfiles(environment);// 绑定一些值bindToSpringApplication(environment);if (!this.isCustomEnvironment) {environment = new EnvironmentConverter(getClassLoader()).convertEnvironmentIfNecessary(environment,deduceEnvironmentClass());}ConfigurationPropertySources.attach(environment);return environment;
}
(5)创建IOC容器
// org.springframework.boot.SpringApplication#createApplicationContext
protected ConfigurableApplicationContext createApplicationContext() {// 根据项目类型(Servlet)创建容器,当前会创建 AnnotationConfigServletWebServerApplicationContextreturn this.applicationContextFactory.create(this.webApplicationType);
}
(6)准备ApplicationContext IOC容器的基本信息
// org.springframework.boot.SpringApplication#prepareContext
private void prepareContext(DefaultBootstrapContext bootstrapContext, ConfigurableApplicationContext context,ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,ApplicationArguments applicationArguments, Banner printedBanner) {// 保存基础环境信息context.setEnvironment(environment);// IOC容器的后置处理流程(注册一些组件、读取配置文件资源、注册资源加载器、准备类型转换器等等)postProcessApplicationContext(context);// 应用初始化器:applyInitializers// 遍历所有的 ApplicationContextInitializer 。调用 initialize方法。来对ioc容器进行初始化扩展功能applyInitializers(context);// 遍历所有的 listener 调用 contextPrepared方法。listeners.contextPrepared(context);bootstrapContext.close(context);if (this.logStartupInfo) {logStartupInfo(context.getParent() == null);logStartupProfileInfo(context);}// Add boot specific singleton beansConfigurableListableBeanFactory beanFactory = context.getBeanFactory();beanFactory.registerSingleton("springApplicationArguments", applicationArguments);if (printedBanner != null) {beanFactory.registerSingleton("springBootBanner", printedBanner);}if (beanFactory instanceof DefaultListableBeanFactory) {((DefaultListableBeanFactory) beanFactory).setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);}if (this.lazyInitialization) {context.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor());}// Load the sourcesSet<Object> sources = getAllSources();Assert.notEmpty(sources, "Sources must not be empty");load(context, sources.toArray(new Object[0]));// 所有的监听器 调用 contextLoaded。通知所有的监听器 contextLoadedlisteners.contextLoaded(context);
}
(7)IOC容器的经典初始化过程
spring容器创建流程参考博文
spring系列-注解驱动原理及源码-spring容器创建流程-CSDN博客
注意:
spring默认的onRefresh()方法是空的,springboot将onRefresh()方法重写,加入了tomcat的启动。
// org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext#onRefresh
protected void onRefresh() {super.onRefresh();try {// 创建一个web应用createWebServer();}catch (Throwable ex) {throw new ApplicationContextException("Unable to start web server", ex);}
}
springboot嵌入式tomcat启动原理参考博文:
https://blog.csdn.net/A_art_xiang/article/details/122435665
(8)调用所有runners
默认是没有runner。
// org.springframework.boot.SpringApplication#callRunners
private void callRunners(ApplicationContext context, ApplicationArguments args) {List<Object> runners = new ArrayList<>();// 获取容器中的 ApplicationRunnerrunners.addAll(context.getBeansOfType(ApplicationRunner.class).values());// 获取容器中的 CommandLineRunnerrunners.addAll(context.getBeansOfType(CommandLineRunner.class).values());// 合并所有runner并且按照@Order进行排序AnnotationAwareOrderComparator.sort(runners);// 遍历所有的runner。调用 run 方法for (Object runner : new LinkedHashSet<>(runners)) {if (runner instanceof ApplicationRunner) {callRunner((ApplicationRunner) runner, args);}if (runner instanceof CommandLineRunner) {callRunner((CommandLineRunner) runner, args);}}
}
runner是一个接口:
@FunctionalInterface
public interface ApplicationRunner {/*** Callback used to run the bean.* @param args incoming application arguments* @throws Exception on error*/void run(ApplicationArguments args) throws Exception;
}
springboot启动流程,手把手打断点一步步看运行步骤相关推荐
- SpringBoot启动流程分析(四):IoC容器的初始化过程
SpringBoot系列文章简介 SpringBoot源码阅读辅助篇: Spring IoC容器与应用上下文的设计与实现 SpringBoot启动流程源码分析: SpringBoot启动流程分析(一) ...
- Java面试--SpringBoot启动流程
一.SpringBoot是什么 SpringBoot 是依赖于 Spring 的,比起 Spring,除了拥有 Spring 的全部功能以外,SpringBoot 无需繁琐的 Xml 配置,这取决于它 ...
- SpringBoot 启动流程(细节拉满)
SpringBoot 启动流程(细节拉满) 网上搜了一下,这方面网上的资料不少,有些从@SpringBootApplication来入手讲.个人不能苟同吧,讲一讲我的理解.还有一些讲的比较笼统,我来写 ...
- SpringBoot启动流程解析
写在前面: 由于该系统是底层系统,以微服务形式对外暴露dubbo服务,所以本流程中SpringBoot不基于jetty或者tomcat等容器启动方式发布服务,而是以执行程序方式启动来发布(参考下图ke ...
- Springboot启动流程分析(四):完成启动流程
目录 一 添加BeanPostProcessors到IOC容器 二 国际化支持 三 初始化监听器的多路播放器 四 刷新容器 五 注册监听器到IOC容器的多播器 六 完成bean的大规模实例化 6.1 ...
- SPRINGBOOT启动流程及其原理
Spring Boot.Spring MVC 和 Spring 有什么区别? 分别描述各自的特征: Spring 框架就像一个家族,有众多衍生产品例如 boot.security.jpa等等:但他们的 ...
- SpringBoot启动流程简要
SpringBoot启动流程大概: 初始化SpringApplication 根据项目的配置情况和Conditional条件来推断是否是一个Web应用. 读取所有jar包下面spring.factor ...
- 高级面试题--SpringBoot启动流程解析
写在前面: 由于该系统是底层系统,以微服务形式对外暴露dubbo服务,所以本流程中SpringBoot不基于jetty或者tomcat等容器启动方式发布服务,而是以执行程序方式启动来发布(参考下图ke ...
- SpringBoot入门到精通-SpringBoot启动流程(七)
定义自己的starter SpringBoot入门到精通-Spring的注解编程(一) SpringBoot入门到精通-SpringBoot入门(二) SpringBoot入门到精通-Spring的基 ...
最新文章
- C#中Path类的常用方法
- web.py开发web 第四章 Sqlalchemy(事件监听与初始化)
- ArrayList 与 LinkedList 底层实现
- 怎么通过media foundation将图像数据写入虚拟摄像头_千倍成本压缩!特斯拉开发虚拟激光雷达,替代最贵自动驾驶传感器...
- python 数据科学 包_什么时候应该使用哪个Python数据科学软件包?
- java fileinputstream.read(byte[])_Java分享笔记:FileInputStream流的 read()方法 和 read(byte[] b)方法...
- java代码ftp重命名未生效_java使用apache commons连接ftp修改ftp文件名失败原因
- python excel导入oracle数据库_【Python代替Excel】12:Python操作oracle数据库
- 两栈共享存储空间算法
- Android 中发送短信
- php网站整合ck播放器,CKplayer 整合播放M3U8视频
- 读书笔记 之《软件架构设计: 大型网站技术架构与业务架构融合之道》
- Android 10.0 Launcher3 抽屉式(双层)app列表排序
- 学习机器学习开始的一些别人的看法
- 一文读懂数据库的文本数据类型:CHAR,VARCHAR,TEXT,BLOG,NCHAR、NVARCHAR、NTEXT
- 物联网|物联网领域常用通信类型
- TI飞控出现联系方式,Ti飞控芯片锁了解决办法
- 【管理系统中计算机应用】决策支持系统
- 进销存ERP系统、销售单、采购单、退货单、库存管理、库存盘点、调拨、借入、借出、出库、入库、归还单、收款单、付款单、资金流水、销售报表、采购报表、库存报表、财务报表、商品库、电商erp、连锁erp 1
- QT CREATOR出现no Qt platform plugin问题
热门文章
- [转]Linux下的Makefile
- pgsql的存储过程调用mysql_PostgreSQL存储过程循环调用方式
- 建标库标准怎么导出pdf_保存和导出PDF文档,这款OCR文字识别软件能做到
- idea实现抽象类的所有抽象方法_深入理解Java的接口和抽象类
- 人工智能论坛_浙江大学人工智能论坛在北京召开
- 关于surface安装foxmail附件预览失效解决方案
- Linux关闭开关机动画,centos7删除开机动画及修改启动菜单
- python入门之函数调用第一关_零基础学习 Python 之与函数的初次相见
- python常用编译器和解释器的区别_Python常用编译器原理及特点解析
- go语言和java比_去过大场面试后,java程序员有没有必要转学Go语言?