SpringBoot启动过程深度解析——概述
发布日期:2023-09-20 01:41:06 浏览次数:1 分类:技术文章

本文共 12995 字,大约阅读时间需要 43 分钟。

SpringBoot启动过程深度解析–概述


文章使用 spring 相关版本信息:

spring-boot 2.3.4.RELEASE
spring-core 5.2.9.RELEASE
spring-context 5.2.9.RELEASE
spring-web 5.2.9.RELEASE


前言

spring和springboot有什么关系?

springBoot是基于spring框架开发的,springBoot主要用spring的IOC的流程进行扩展开发spring框架解决的问题:	1.IOC 依赖注入和控制反转(把相互依赖的Bean对象,通过注解/xml的配置依赖关系,交给spring帮我们创建、注入和管理这些Bean)	2.在spring处理Bean对象的各个环节中,提供了很多扩展方法,方便在Bean创建过程执行一些自定义的操作(代理,类型转换,解析自定义注解等等)	3.是一个运行和部署简单的框架	springBoog框架解决的问题:	1.自动装配 (通过@Configuration / spring.factories文件,都可以加载配置类,用于注册自定义满足条件的Bean)	2.快速引入依赖,快速使用依赖( 引入对应依赖 spring-boot-starter-XXXX包,一般就能使用了,也是用自动装配的功能实现的)	3.丰富的依赖包选择

spring和springboot启动的几种方式

spring启动的方式:	1.通过XXXXXApplicationContext.refresh()启动	springBoot启动方式:	1.通过XXXXXApplicationContext.refresh()启动	2.通过启动

springboot如何开启自动装配的方式

1.在启动类/配置类 使用注解@EnableAutoConfiguration(通常通过组合注解使用@SpringBootApplication)

一、SpringBoot启动过程深度解析

接下来的文章就以SpringApplication.run的启动方式讲解

@SpringBootApplicationpublic class Main {
public static void main(String[] args) {
new SpringApplication(Main.class).run(); }}

SpringApplication.run启动的主要脉络流程图:

SpringApplication.run启动的主要脉络流程图

1.SpringApplication的创建:

SpringApplication对象创建过程,只加载一些简单的配置:	1.根据环境计算当前应该创建的Web类型	2.从"META-INF/spring.factories"读取ApplicationContextInitializer类的实例	3.从"META-INF/spring.factories"读取ApplicationListener类的实例	4.通过当前调用栈,获取Main方法所在类
/**	可以通过此类快速启动一个spring应用,可以传入一些加载的配置类来引导启动**/public class SpringApplication {
public SpringApplication(ResourceLoader resourceLoader, Class
... primarySources) {
this.resourceLoader = resourceLoader; Assert.notNull(primarySources, "PrimarySources must not be null"); //记录传入的配置文件 this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources)); //根据环境计算当前应该创建的Web类型 this.webApplicationType = WebApplicationType.deduceFromClasspath(); /** 解析这些ApplicationContextInitializer的作用请看【详细链接:】 设置应用上线文初始化器,从"META-INF/spring.factories"读取ApplicationContextInitializer类的实例。(默认一共7个) org.springframework.boot.autoconfigure.SharedMetadataReaderFactoryContextInitializer org.springframework.boot.autoconfigure.logging.ConditionEvaluationReportLoggingListener org.springframework.boot.context.ConfigurationWarningsApplicationContextInitializer org.springframework.boot.context.ContextIdApplicationContextInitializer org.springframework.boot.context.config.DelegatingApplicationContextInitializer org.springframework.boot.rsocket.context.RSocketPortInfoApplicationContextInitializer org.springframework.boot.web.context.ServerPortInfoApplicationContextInitializer **/ setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class)); /** 解析这些ApplicationListener的作用请看【详细链接:】 设置监听器,从"META-INF/spring.factories"读取ApplicationListener类的实例。(一共11个) org.springframework.boot.autoconfigure.BackgroundPreinitializer org.springframework.boot.ClearCachesApplicationListener org.springframework.boot.builder.ParentContextCloserApplicationListener org.springframework.boot.cloud.CloudFoundryVcapEnvironmentPostProcessor org.springframework.boot.context.FileEncodingApplicationListener org.springframework.boot.context.config.AnsiOutputApplicationListener org.springframework.boot.context.config.ConfigFileApplicationListener org.springframework.boot.context.config.DelegatingApplicationListener org.springframework.boot.context.logging.ClasspathLoggingApplicationListener org.springframework.boot.context.logging.LoggingApplicationListener org.springframework.boot.liquibase.LiquibaseServiceLocatorApplicationListener **/ setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class)); //推断主入口应用类,通过当前调用栈,获取Main方法所在类,并赋值给mainApplicationClass this.mainApplicationClass = deduceMainApplicationClass(); } }

2.SpringApplication.run的执行:

1.创建并启动计时监控StopWatch2.设置系统属性“java.awt.headless”的值【建议在缺少显示屏、键盘或者鼠标的应用开启】3.从SpringFactories文件加载SpringApplicationRunListener实现类4.发布事件:ApplicationStartingEvent5.解析run方法入参命令【类似于 --foo=bar 】6.准备环境变量,发布事件:ApplicationEnvironmentPreparedEvent7.设置参数spring.beaninfo.ignore默认TRUE8.打印Banner9.根据不同的应用类型初始化不同的上下文类Context10.从SpringFactories文件加载SpringBootExceptionReporter异常报告器11.加载BeanDefinition【包括自动装配的扫描】12.执行spring的标准初始化过程【AbstractApplicationContext.refresh() 】13.应用上下文刷新后置处理,做一些扩展功能14.停止计时监控15.发布应用上下文启动监听事件 ApplicationStartedEvent16.执行所有的Runner运行器17.发布应用上下文就绪事件 ApplicationReadyEvent
public ConfigurableApplicationContext run(String... args) {
//开启记录启动过程的秒表器 //允许对多个任务进行计时,公开每个命名任务的总运行时间和运行时间,从Spring Framework 5.2开始,运行时间以纳秒为单位进行跟踪和报告 StopWatch stopWatch = new StopWatch(); //秒表器开始计时 stopWatch.start(); //声明spring容器 ConfigurableApplicationContext context = null; //声明spring异常报告器 Collection
exceptionReporters = new ArrayList<>(); // 设置java.awt.headless变量 // 1、如果设置headless模式为true,则程序是无显示器模式 // 2、为了提高计算效率和适配性我们可以使用这种模式,关闭图形显示等功能可以大大节省设备的计算能力 // 3、通常B/S型Web应用运行于无显示设备、驱动的服务器端环境中,但是有使用AWT绘图接口的可能(例如:用Images、Fonts接口生成图片验证码) // 所以给Tomcat、Weblogic附加参数-Djava.awt.headless=true,强制使用Headless版本的AWT实现类,就能避免图形环境缺失所导致的程序出错 configureHeadlessProperty(); //读取META-INF/spring.factories接口SPI的实现类配置,初始化SpringApplicationRunListener实现类 //SpringApplicationRunListener是springApplication启动过程的监听器 SpringApplicationRunListeners listeners = getRunListeners(args); //SpringApplicationRunListener发布开始启动事件 listeners.starting(); try {
//解析启动命令封装到 applicationArguments对象 ApplicationArguments applicationArguments = new DefaultApplicationArguments(args); //初始化所有环境变量,SpringApplicationRunListener发布环境准备完成事件【详细链接...】 ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments); /**设置spring.beaninfo.ignore 1.如果启动过程不需要对Bean信息的重复访问(Introspector.getBeanInfo(Class)调用),请设置为true,否则启动过程将变得昂贵**/ configureIgnoreBeanInfo(environment); //打印Banner【详细链接...】 Banner printedBanner = printBanner(environment); /**根据web类型创建对应的ConfigurableApplicationContext !!!父类AnnotationConfigServletWebServerApplicationContext无参构造会做以下两件事 ** 1.创建一个注解BeanDefinition读取器AnnotatedBeanDefinitionReader并且注册一些用于注册Bean的自带增强器到BeanDefinitionRegistry中 -- 1.DefaultListableBeanFactory设置依赖顺序比较器:AnnotationAwareOrderComparator -- 2.DefaultListableBeanFactory设置是否能注入当前Bean的判断器:ContextAnnotationAutowireCandidateResolver -- 3.注入Bean:ConfigurationClassPostProcessor -- 4.注入Bean:AutowiredAnnotationBeanPostProcessor -- 5.如果满足JSR-250规范的话(判断是否存在javax.annotation.Resource),注入Bean:CommonAnnotationBeanPostProcessor -- 6.如果满足(判断是否存在javax.persistence.EntityManagerFactory),注入Bean:PersistenceAnnotationBeanPostProcessor -- 7.注入Bean:EventListenerMethodProcessor -- 8.注入Bean:DefaultEventListenerFactory ** 2.创建一个类路径BeanDefinition扫描器ClassPathBeanDefinitionScanner并且添加一些需要被创建Bean的注解到ClassPathBeanDefinitionScanner的需要的过滤器中 -- 本步骤主要是添加过滤器,对 includeFilters 赋值。 注册过滤器 @Component,@Controller @Service、 @Repository 也会被添加进去。也会注册添加 JSR-250 的 @ManagedBean 和 JSR-330 的 @Named 注解。**/ context = createApplicationContext(); //通过META-INF/spring.factories初始化SpringBootExceptionReporter实现类 exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class, new Class[] {
ConfigurableApplicationContext.class }, context); /**准备和填充ApplicationContext上下文属性【详细链接...】 1. 设置环境对象 2. 增强上下文 ** 1.如果有配置,则注册BeanName构造器Bean对象 ** 2.如果有配置,则设置资源加载器resourceLoader对象 ** 3.如果有配置,则设置属性ConversionService 3. 执行所有ApplicationContextInitializer实现类的initialize方法【详细链接...】 4. SpringApplicationRunListener发布上下文准备完成事件 5. 打印profile环境 6. 注册单例Bean:springApplicationArguments 7. 注册单例Bean:springBootBanner 8. 如果是DefaultListableBeanFactory,设置是否允许BeanDefinition重写 9. 是否懒加载,是的话注册一个BeanFactory增强处理器LazyInitializationBeanFactoryPostProcessor 10. 获取应用程序源【应用程序源:用于创建应用程序上下文的其他源。源可以是:类名、包名或 XML 资源位置】 11. 根据应用程序源, 用BeanDefinitionLoader进行加载程序源的BeanDefinition【详细链接...】 ** 程序源是类: AnnotatedBeanDefinitionReader#doRegisterBean通过注解进行加载BeanDefinition ** 1.根据程序源类@Conditional 判断是否跳过此程序源的扫描 ** 2.程序源的abd设置InstanceSupplier(创建Bean实例的回调) ** 3.程序源的abd设置程序源类@Scope配置的Bean作用域,代理模式(默认单例模式+无代理) ** 4.扫描程序源类上的直接注解,按照注解设置Bean别名 ** 5.处理程序源类上的公共注解AnnotationConfigUtils.processCommonDefinitionAnnotations(abd) -- 1.是否懒加载@Lazy -- 2.是否@Primary -- 3.是否依赖加载@DependsOn -- 4.设置角色@Role -- 5.设置描述@Description ** 6.执行BeanDefinitionCustomizer实现类的customize方法(用于自定义给定Bean定义的回调,用于扩展) ** 7.包装abd成BeanDefinitionHolder对象 //带有名称和别名的 BeanDefinition 的持有者 ** 8.根据@Scope代理方式,进行BeanDefinition的修改定义 ** 9.注册程序源的BeanDefinition到BeanDefinitionRegistry 12. SpringApplicationRunListener发布上下文加载完成事件**/ prepareContext(context, environment, listeners, applicationArguments, printedBanner); /** 刷新容器refreshContext【Spring容器启动公共逻辑!!重要】【详细链接...】 1.此处额外执行操作: 将创建一个钩子线程SpringContextShutdownHook,注册到Java虚拟机的关闭挂钩线程集合中,用于java虚拟机关闭时调用执行关闭spring容器方法 (org.springframework.context.support.AbstractApplicationContext#doClose)**/ refreshContext(context); //刷新容器之后执行的扩展方法afterRefresh【详细链接...】 afterRefresh(context, applicationArguments); //stopWatch秒表停止记录spring启动过程 stopWatch.stop(); if (this.logStartupInfo) {
//打印spring已经启动的日志包含启动事件 new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch); } //SpringApplicationRunListener发布spring已经启动完成的事件 listeners.started(context); //执行一些运行器: ApplicationRunner实现类和 CommandLineRunner实现类【扩展点】 callRunners(context, applicationArguments); } catch (Throwable ex) {
handleRunFailure(context, ex, exceptionReporters, listeners); throw new IllegalStateException(ex); } try {
//SpringApplicationRunListener发布spring正在运行的事件 listeners.running(context); } catch (Throwable ex) {
handleRunFailure(context, ex, exceptionReporters, null); throw new IllegalStateException(ex); } return context; }

3.AbstractApplicationContext.refresh的执行:

1.容器刷新前的准备工作(记录启动时间、容器状态、环境变量对象、准备监听器和事件的集合对象)2.创建容器对象:DefaultListableBeanFactory3.beanFactory的准备工作,对各种属性进行填充4.beanFactory扩展工作5.调用各种beanFactory处理器6.注册bean处理器7.为上下文初始化message源,即不同语言的消息体,国际化处理8.初始化事件监听多路广播器【Web容器的创建】9.在所有注册的bean中查找listener bean,注册到消息广播器中10.初始化剩下的单实例(非懒加载的)11.完成刷新过程,通知生命周期处理器lifecycleProcessor刷新过程,同时发出ContextRefreshEvent事件12.最终清除一些缓存
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// Prepare this context for refreshing. /** * 容器刷新前的准备工作(记录启动时间、容器状态、环境变量对象、准备监听器和事件的集合对象) */ prepareRefresh(); // Tell the subclass to refresh the internal bean factory. // 创建容器对象:DefaultListableBeanFactory ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); // Prepare the bean factory for use in this context. // beanFactory的准备工作,对beanFactory各种属性进行填充 prepareBeanFactory(beanFactory); try {
// Allows post-processing of the bean factory in context subclasses. // 子类覆盖方法做额外的处理,子类扩展方法 postProcessBeanFactory(beanFactory); // Invoke factory processors registered as beans in the context. // 调用各种beanFactory处理器 invokeBeanFactoryPostProcessors(beanFactory); // Register bean processors that intercept bean creation. // 注册bean处理器,这里只是注册功能,真正调用的是getBean方法 registerBeanPostProcessors(beanFactory); // Initialize message source for this context. // 为上下文初始化message源,即不同语言的消息体,国际化处理 initMessageSource(); // Initialize event multicaster for this context. // 初始化事件监听多路广播器 initApplicationEventMulticaster(); // Initialize other special beans in specific context subclasses. // 留给子类来初始化其他的bean // 【Web容器的创建】 onRefresh(); // Check for listener beans and register them. // 在所有注册的bean中查找listener bean,注册到消息广播器中 registerListeners(); // Instantiate all remaining (non-lazy-init) singletons. // 初始化剩下的单实例(非懒加载的) finishBeanFactoryInitialization(beanFactory); // Last step: publish corresponding event. // 完成刷新过程,通知生命周期处理器lifecycleProcessor刷新过程,同时发出ContextRefreshEvent通知别人 finishRefresh(); } catch (BeansException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - " + "cancelling refresh attempt: " + ex); } // Destroy already created singletons to avoid dangling resources. // 为防止bean资源占用,在异常处理中,销毁已经在前面过程中生成的单件bean destroyBeans(); // Reset 'active' flag. // 重置active标志 cancelRefresh(ex); // Propagate exception to caller. throw ex; } finally {
// Reset common introspection caches in Spring's core, since we // might not ever need metadata for singleton beans anymore... // 释放各种缓存 resetCommonCaches(); } } }

转载地址:https://blog.csdn.net/weixin_39072857/article/details/128780714 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:SpringBoot启动过程深度解析——自动装配-启动过程解析
下一篇:SpringBoot启动过程深度解析——WebApplicationType

发表评论

最新留言

哈哈,博客排版真的漂亮呢~
[***.90.31.176]2023年09月21日 05时11分49秒