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

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启动流程图
案例发展特色产业助力乡村振兴安徽省晨光村铺就致富路发展特色产业助力乡村振兴(第26期)。十四五规划提出全面实施乡村振兴战略。中共中央国务院关于全面推进乡村振兴加快农业农村现代化的意见也提出构建现代乡村产业体系,深入挖掘继承创新优秀银川周边自驾游10个好去处线路推荐,这些地方你都知道吗?旅行是一种追寻,尽可能地去更多的地方,寻找不一样的新鲜与感动旅行是一种分享。下面跟随小编一起去看看吧!春风十里,不如景区有你,赶紧行动吧!1。西夏王陵西夏历代帝王的陵寝,位于西夏区球赛间隙的旅行经过上述讨论,球赛间隙的旅行因何而发生?这样看来,球赛间隙的旅行,发生了会如何,不发生又会如何。非洲曾经提到过,最灵繁的人也看不见自己的背脊。这启发了我,了解清楚球赛间隙的旅行到底了解更多标志性古塔应县木塔,即释迦塔,全称佛宫寺释迦塔,位于山西省朔州市应县城西北佛宫寺内。建于辽清宁二年(宋至和三年公元1056年),金明昌六年(南宋庆元一年公元1195年)增修完毕,是中国现存最求真心也是一种贪婪,你不贪就不会被骗要求别人对你一片真心,也是一种贪婪。真心到底是什么?时时刻刻把你的感受放在第一位,这辈子对你绝对忠诚,是你和他妈妈同时落水,毫不犹豫地先救你。过情人节不但要送礼物,还得真心实意地送世界杯养生中医有话要说饮食篇四年一届的足球世界杯,是我们足球爱好者的节日,很多球迷朋友都会在世界杯期间,约上几个朋友,一起踢球,看球,侃球,可能免不了吃饭,喝酒。可是凡事要适可而止,不可过量,以免影响我们的健低情商女人和高情商女人,区别在哪里?抄书打卡第一天高情商的女人会活成此生最富有的女人,什么都不缺,低情商的女人什么都没有1低情商的人爱哭,高情商的人爱笑2低情商的人只说,高情商的人只做3低情商爱管,高情商的人爱放4低赞美你学会了吗?让说话成为你的一种优势恰当的赞美能产生一种巨大的力量,所有人都希望听到赞美的语言,赞美能让人心情舒畅,会使人与人之间的隔阂越来越小,拉近人与人之间的距离感。学会赞美别人是一种艺术,一种品德。取悦人心会做数据自己会说话11月11日,国家发布进一步优化疫情防控二十条措施。随之而来,诸相丛生。石家庄郑州徐州乌鲁木齐一个个城市先后上了热搜。这些天里,感觉互联网世界的舆论场分成了至少两层官方发布会和媒体比利时内讧!阿扎尔与德布劳内激烈争吵,丁丁因友妻门不和裤袜说话11月29日消息,自从比利时队02输给摩洛哥之后,球队内部曝出了一系列不和谐的声音,据比利时媒体爆料,阿扎尔在昨日与德布劳内维尔通亨爆发激烈争吵,而队内多人存在矛盾。卡塔尔世界杯F柳岩的身材到底有多好?看图说话,让你明白什么是好身材都说柳岩是性感女神。这话一点都不假。不说其他的,她的身材是非常好的。在这个到处都是美女的时代,好颜值好身材多不胜数。能在众多好身材,好颜值的美女当中独树一格。简单的黑色搭配,调皮又
晚间公告丨1月16日这些公告有看头品大事宝明科技拟62亿元马鞍山市投建复合铜箔生产基地宝明科技公告,为实现在新能源电池行业的布局,公司拟以8000万元设立全资子公司安徽宝明新材料科技有限公司,在马鞍山市宁马新型功能资治通鉴9赵襄子有五个儿子,为什么却坚持要传位给侄孙?关于一代雄主赵襄子的最后一个故事,是他的身后事,赵氏家业要传位给谁?一出来混,迟早要还的!资治通鉴记载,赵襄子对当初兄长伯鲁被废一直介怀于心,因此,他虽然有五个儿子,却不肯立儿子为中世纪欧洲科学的传播交流流入与发展欧洲的中世纪通常被称为黑暗时期,但在艰难的环境中科学仍有所发展。通过对中世纪大翻译运动大学教育技术自身传播等科学传播交流现象的分析,人们能够更加客观清晰的了解这段科学发展的艰难之路历史上的今天2023。01。15历史上的今天今天是2023年的第15天,腊月二十四扫尘日北方小年南方。8年王莽建立新朝,西汉结束。1913年李烈钧抗拒袁世凯。1916年饥民大闹上海。1918年中国护法战争岑春煊在古代历史上四大清官,包拯排第三第一位最后竟然被腰斩了!第四位于成龙字北溟,号于山,山西永宁州(今山西省吕梁市方山县)人。清朝初年名臣。于成龙是大器晚成的类型,在担任罗城县知县之前,由于当时政局不稳,两任知县一死一逃。但是于成龙上任两年合纵连横张仪秦国的大外交家自古以来外交都是一个国家不可或缺的一部分。他们的身上背负着人民的期待,背负着沉甸甸的责任,古时候有晏子使楚。面对楚人的咄咄逼人,将小门作为大门让其侧身进入,面对这些,他用刚硬的态度趣味中国简史(47)焚书坑儒公元前221年,秦始皇灭六国统一华夏建立了秦朝,废分封行郡县,中华民族历史上第一次进入大一统时代。秦朝疆域东南两面到大海,北到今天的长城一线,西到甘肃,面积达到了约350万平方公里元朝刘国杰投身战场,屡屡立功刘国杰是元代杰出的军事将领,刘国杰家族历经由金至元的迁转之后依凭军功再度起家,为元廷立下汗马功劳。投身战场刘国杰作为深受元世祖元成宗信任,驰名朝野的武将,他的功名显然与其一生的戎马郑和献麒麟,引朱棣龙颜大悦,而今画像公开令人啼笑皆非永乐三年,为证明朝国力强盛,扩展海外交易,明成祖朱棣派郑和下西洋扩展海外交流,发展经济。郑和下西洋这一举措虽对明朝的经济造成了巨大的影响,但也因此获得了许多令人满意的成就,万国来朝浅谈宋代私盐的市场供给食盐关系到国计民生,自古以来都是统治阶级重点的关注对象。早在春秋时期,齐国就通过垄断盐铁实行了富国强兵,成为春秋首霸。汉武帝时,正式将盐铁国营,以所获之利为军费,使得四夷臣服。宋代为什么古代中原王朝容易丢失河套地区先针对下面另一个回答说一句,能不能发展农业真不能只看400mm等降水量线。有个常见的说法是明长城与400mm降水量线重合,这个并不准确。宣大地区,一般略低于400mm兰州银川(古称