范文健康探索娱乐情感热点
投稿投诉
热点动态
科技财经
情感日志
励志美文
娱乐时尚
游戏搞笑
探索旅游
历史星座
健康养生
美丽育儿
范文作文
教案论文
国学影视

springboot启动流程源码解析(带流程图)

  大致流程如下:
  1. 初始化SpringApplication,从META-INF下的spring.factories读取ApplicationListener/ApplicationContextInitializer
  2.运行SpringApplication的run方法
  3.读取项目中环境变量、jvm配置信息、配置文件信息等
  4.创建Spring容器对象(ApplicationContext)
  5. 利用ApplicationContextInitializer初始化Spring容器对象,读取启动类
  6.调用spring的refresh加载IOC容器、自动配置类,并创建bean、servlet容器等信息
  7.springboot会调用很多监听器
  8.如果启动时发生异常,则发送ApplicationFailedEvent事件
  下面对上述流程进行 源码细化分析 ,首先调用SpringApplication.run启动springboot应用:  @SpringBootApplication(exclude = DruidDataSourceAutoConfigure.class) @EnableTransactionManagement(proxyTargetClass = true) @Import(MyDynamicDataSourceConfig.class) public class MySpringBootApplication {     public static void main(String[] args) {         SpringApplication.run(MySpringBootApplication.class, args);     } }
  进入run方法后,会进行SpringApplication进行启动,分两大步,第一步初始化SpringApplication,第二步调用run方法:  public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {    return new SpringApplication(primarySources).run(args); }
  第一步初始化SpringApplication, new SpringApplication(primarySources)的流程如下(具体方法含义参考注释):  public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {    this.resourceLoader = resourceLoader;    Assert.notNull(primarySources, "PrimarySources must not be null");    this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));   // 根据classpath下的类,推算当前web应用类型(REACTIVE/SERVLET/NONE)    this.webApplicationType = WebApplicationType.deduceFromClasspath();   // 获取BootstrapRegistryInitializer对象,从META-INF/spring.factories中读取key为BootstrapRegistryInitializer,并实例化出对象  // BootstrapRegistryInitializer的作用是可以初始化BootstrapRegistry   this.bootstrapRegistryInitializers = new ArrayList<>(          getSpringFactoriesInstances(BootstrapRegistryInitializer.class));   //去spring.factories中去获取所有key:org.springframework.context.ApplicationContextInitializer为了初始化Spring容器ApplicationContext对象(可以利用  //ApplicationContextInitializer向Spring容器中添加ApplicationListener)   setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));   //去spring.factories中去获取所有key: org.springframework.context.ApplicationListener,ApplicationListener是Spring中的监听器    setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));   //推测main()方法所在的类    this.mainApplicationClass = deduceMainApplicationClass(); }
  第二步调用run方法, 初始化完SpringApplication开始运行run方法,源码如下: public ConfigurableApplicationContext run(String... args) {    long startTime = System.nanoTime();//记录时间    //创建DefaultBootstrapContext对象,利用BootstrapRegistryInitializer初始化DefaultBootstrapContext对象    DefaultBootstrapContext bootstrapContext = createBootstrapContext();    ConfigurableApplicationContext context = null;   // 开启了Headless模式:    configureHeadlessProperty();   //获取SpringApplicationRunListeners, //SpringBoot提供了一个EventPublishingRunListener,它实现了SpringApplicationRunListener接口   //spring会利用这个类,发布一个ApplicationContextInitializedEvent事件,可以通过定义ApplicationListener来消费这个事件    SpringApplicationRunListeners listeners = getRunListeners(args);   // 发布ApplicationStartingEvent事件,在运行开始时发送    listeners.starting(bootstrapContext, this.mainApplicationClass);    try {      // 根据命令行参数 实例化一个ApplicationArguments       ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);      // 预初始化环境(见下面的源码分析): 读取环境变量(操作系统的环境变量/JVM的环境变量),读取配置文件信息(基于监听器,会利用EventPublishingRunListener发布一个ApplicationEnvironmentPreparedEvent事件, 		//默认会有一个EnvironmentPostProcessorApplicationListener来处理这个事件,当然也可以通过自定义ApplicationListener来处理这个事件,当ApplicationListener接收到这个事件之后,就会解析application.properties、application.yml文件,    //并添加到Environment中)       ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments);       configureIgnoreBeanInfo(environment);       Banner printedBanner = printBanner(environment);// 打印Banner      //据webApplicationType创建不同的Spring上下文容器(有三种)       context = createApplicationContext();       context.setApplicationStartup(this.applicationStartup);      //预初始化spring上下文,见下面的源码分析       prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);      //刷新Spring容器,这一步中创建并初始化bean,创建并启动tomacat等(以tomcat为例,调到ServletWebServerApplicationContext的createWebServer()方法      //最后执行TomcatServletWebServerFactory的getWebServer方法)      refreshContext(context);       afterRefresh(context, applicationArguments);       Duration timeTakenToStartup = Duration.ofNanos(System.nanoTime() - startTime);       if (this.logStartupInfo) {          new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), timeTakenToStartup);       }      //发布ApplicationStartedEvent事件和AvailabilityChangeEvent事件       listeners.started(context, timeTakenToStartup);      // 获取Spring容器中的ApplicationRunner/CommandLineRunner类型的Bean,并执行run方法       callRunners(context, applicationArguments);    }    catch (Throwable ex) {       handleRunFailure(context, ex, listeners);//发布ApplicationFailedEvent事件       throw new IllegalStateException(ex);    }    try {       Duration timeTakenToReady = Duration.ofNanos(System.nanoTime() - startTime);      //发布ApplicationReadyEvent事件和AvailabilityChangeEvent事件       listeners.ready(context, timeTakenToReady);    }    catch (Throwable ex) {       handleRunFailure(context, ex, null);//发布ApplicationFailedEvent事件       throw new IllegalStateException(ex);    }    return context; }
  预初始化环境,创建Environment对象源码解析: private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners,       DefaultBootstrapContext bootstrapContext, ApplicationArguments applicationArguments) {    // 根据webApplicationType 创建Environment 创建就会读取: java环境变量和系统环境变量    ConfigurableEnvironment environment = getOrCreateEnvironment();   // 将命令行参数读取环境变量中    configureEnvironment(environment, applicationArguments.getSourceArgs());   // 将@PropertieSource的配置信息 放在第一位,它的优先级是最低的    ConfigurationPropertySources.attach(environment);   // 发布了ApplicationEnvironmentPreparedEvent 的监听器 读取了全局配置文件    listeners.environmentPrepared(bootstrapContext, environment);   // 将所有spring.main 开头的配置信息绑定到SpringApplication中    DefaultPropertiesPropertySource.moveToEnd(environment);    Assert.state(!environment.containsProperty("spring.main.environment-prefix"),          "Environment prefix cannot be set via properties.");    bindToSpringApplication(environment);    if (!this.isCustomEnvironment) {       EnvironmentConverter environmentConverter = new EnvironmentConverter(getClassLoader());       environment = environmentConverter.convertEnvironmentIfNecessary(environment, deduceEnvironmentClass());    }    ConfigurationPropertySources.attach(environment);//更新PropertySources    return environment; }
  预初始化spring上下文源码解析: private void prepareContext(DefaultBootstrapContext bootstrapContext, ConfigurableApplicationContext context,       ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,       ApplicationArguments applicationArguments, Banner printedBanner) {    context.setEnvironment(environment);    postProcessApplicationContext(context);    applyInitializers(context);// 拿到之前读取到所有ApplicationContextInitializer的组件, 循环调用initialize方法    listeners.contextPrepared(context);// 发布了ApplicationContextInitializedEvent    bootstrapContext.close(context);    if (this.logStartupInfo) {       logStartupInfo(context.getParent() == null);       logStartupProfileInfo(context);    }   // 获取当前spring上下文beanFactory (负责创建bean)    ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();    beanFactory.registerSingleton("springApplicationArguments", applicationArguments);    if (printedBanner != null) {       beanFactory.registerSingleton("springBootBanner", printedBanner);    }    if (beanFactory instanceof AbstractAutowireCapableBeanFactory) {       ((AbstractAutowireCapableBeanFactory) beanFactory).setAllowCircularReferences(this.allowCircularReferences);       if (beanFactory instanceof DefaultListableBeanFactory) {         //在SpringBoot 在这里设置了不允许覆盖, 当出现2个重名的bean 会抛出异常          ((DefaultListableBeanFactory) beanFactory)                .setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);       }    }   // 设置当前spring容器是不是要将所有的bean设置为懒加载    if (this.lazyInitialization) {       context.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor());    }    context.addBeanFactoryPostProcessor(new PropertySourceOrderingBeanFactoryPostProcessor(context));    // Load the sources    Set sources = getAllSources();    Assert.notEmpty(sources, "Sources must not be empty");   // 读取主启动类 (因为后续要根据配置类解析配置的所有bean),将启动类作为配置类注册到Spring容器中    load(context, sources.toArray(new Object[0]));    listeners.contextLoaded(context);//读取完配置类后发送ApplicationPreparedEvent,默认利用EventPublishingRunListener发布一个ApplicationPreparedEvent事件 }
  springboot启动流程图
4号朱婷,意甲最贵外援朱婷,为何要不到自己喜欢的5号或2号球衣据报道,斯坎迪奇女排新赛季将身披4号球衣的朱婷年薪100万欧元,创造意甲联赛历史上最高年薪纪录。作为斯坎迪奇如此重视的球员,朱婷为什么没有得到最喜欢的5号球衣呢?这还要从斯坎迪奇的太惨!曾与邓超杨幂合作的15岁童星,被逼跳楼了01hr最近一个女孩的新闻让人无比揪心,引发了大家的热议。她叫邵一卜,童星出道,曾出演过追梦少年筑梦情缘银河补习班和杨幂邓超颖儿段奕宏等人都合作过。很难想象,身为童星的她,应该会有德云社侯震深夜发文,引发粉丝热议,还是少侯爷的生活趣事多7月3日,德云社侯震深夜发文,对粉丝发出提醒,雨下大了。与此同时,侯震还配上了一张机器猫雨天牧牛,放风筝的图片。而看到这,一时间引发粉丝热议。有的粉丝表示,还是少侯爷的生活趣事多,vivoX60焕发新生,12G256G降1600元后受用户喜欢现在vivoX系列已经成为vivo旗舰中主打性价比的主力军,简单来说如果你要在vivo这个牌子中买到配置高使用体验好但售价又低的机型,那vivoX系列是不二之选。因为在性价比上大增童年回忆西游记开拍四十周年!问题来了,你更喜欢哪个唐僧?1982年7月3日,西游记正式开机,时至今日,已经开拍四十周年啦!西游记这部剧可谓是经典中的经典,可以说没有看过这版西游记的人童年是不完整的吧?我不相信有人童年没看过这部西游记。机童年回忆西游记开拍四十周年!问题来了,你更喜欢哪个唐僧?1982年7月3日,西游记正式开机,时至今日,已经开拍四十周年啦!西游记这部剧可谓是经典中的经典,可以说没有看过这版西游记的人童年是不完整的吧?我不相信有人童年没看过这部西游记。机是骡子是马?中超小将成亮点,东亚杯成最好试金石中超目前已经进行了8轮,作为所谓金元时代(虽然我不赞成这样叫,哪个联赛不是钱堆起来的?)后的第一个赛季。虽然联赛的水平下降了,但也确实给了不少小将展现的机会!这其中最引人注目的当属CBA联赛开赛时间20222023赛季cba将在2022将在10月16日正式开始,其中常规赛将在2022年12月25日迎来第二阶段的赛程,季后赛正赛的开打时间为4月1日。CBA202223赛季的开始是骡子是马?中超小将成亮点,东亚杯成最好试金石中超目前已经进行了8轮,作为所谓金元时代(虽然我不赞成这样叫,哪个联赛不是钱堆起来的?)后的第一个赛季。虽然联赛的水平下降了,但也确实给了不少小将展现的机会!这其中最引人注目的当属CBA联赛开赛时间20222023赛季cba将在2022将在10月16日正式开始,其中常规赛将在2022年12月25日迎来第二阶段的赛程,季后赛正赛的开打时间为4月1日。CBA202223赛季的开始高下立判,梅西做出意外决定!球迷感动C罗学学什么叫球王精神最近大巴黎也即将展开训练营,但梅西,内马尔,姆巴佩这种参加了国家队比赛的球员可以多休息几天。但梅西也非常意外的,提前选择回归了大巴黎。要知道梅西本来可以休息到本月11号的,但球王非
警惕!微信出现这两个界面,马上停手很多人经常会用到微信转账在用微信转账时如果你的手机出现这两个界面一定要提高警惕说明你当前支付存在巨大风险这15分钟,非常关键风险提醒一定要注意冷静下来别上当为了阻止诈骗行为对被害人这些小朋友写的诗,真的是可爱又惊艳,好多大人都自愧不如啊往往小朋友说的话写的句子,才是最纯真可爱又惊艳绝绝下面这些小朋友写的短诗,你看到过几首?这样的句子,以你的才能能否比得过?哈哈哈第一首古诗我把刚写的一首诗,放在太阳底下晒想把它晒黄张靓颖是白出了一个新色号吗,穿着简单的黑裙子,就像合影杀手哈喽,大家好,我是biu时尚,很高兴又和大家分享明星时尚与搭配技巧!希望我的文章让你对时尚更加的感兴趣,让本身就好看的你,更加的有魅力!抹胸的时尚搭配造型是很多礼服的选择当中比较常提高警惕!微信转账时出现这两个界面马上停止交易CNMO新闻现如今,手机功能越来越强大,大多数人出门身上都不会带现金,一般需要付钱的时候都会直接使用手机支付。其中,微信支付就是我们常用的方式之一,在实体店直接扫描二维码,轻松付款小S二女儿想做整形手术,小S劝不动气到哭小S近日在与S妈的Podcast频道老娘的老娘节目中,聊起孩子的叛逆行径,S妈说以前也曾被小孩气到不知道要说什么,就跟孩子们撂话以后妳生小孩,看她们怎么整妳!。如今小S当妈,还真的马上停手!微信有两个界面,弹出就要警惕了至今依然记得,当年使用微信,还是拉着丹妮茜茜无聊胡侃最初是可以发语音的对讲机定位那时的30MB蜂窝数据流量,可以收发几千条语音消息!即使微信加入了网游账户体系,也没改变简洁版QQ而警惕!微信出现这两个界面,马上停手提高警惕,当心诈骗!很多人经常会用到微信转账在用微信转账时如果你的手机出现这两个界面一定要提高警惕说明你当前支付存在巨大风险这15分钟,非常关键风险提醒一定要注意冷静下来别上当为了荣耀70Pro和真我GT2大师探索版的简单配置对比,谁的配置更强荣耀70Pro真我GT2大师探索版性能天玑8000LPDDR5UFS3。1骁龙8Gen1LPDDR5XUFS3。1屏幕6。78英寸120Hz京东方AMOLED柔性曲面屏分辨率265还在穿NikeAdidas?当下最热门的6个跑鞋品牌2020年,全球的减震跑鞋市场规模达到467亿元,并且年复合增长为8。1,其中美国,欧洲和中国市场各占452020左右,在这其中,传统运动强牌的技术迭代放缓,人群覆盖广杂,无法做到自来卷的女孩子,太苦了,太苦了!导语不管是在广场公园或者大街上都会看到有些人长发飘飘,有些人的头发却是弯弯曲曲。当然,抛去自己花钱做的发型之外,还有一些人是天生的自然卷发。自来卷女孩每天醒来的第一件事,可能不是刷生图下的迪丽热巴也很美,穿粉色裙子好减龄,气质优雅又高级其实新疆的美女有很多,尤其是这些新疆的女明星,在娱乐圈中都是一等一的大美女。而迪丽热巴就是其中之一,毕竟她的颜值并不是吹嘘出来的。就算是生图下的迪丽热巴也很美,尤其是穿着粉色裙子,