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

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启动流程图
我与嘉宝共成长6理由童年,以一种独特的方式,在人的一生中,不可替代地存在着,或天真,或烂漫,或无邪,或搞笑和老二去玩,在停车场看到这样几个字老二问爸爸,口口是什么意思?在哪看到的?老二指了指上边这疯传胡歌与小6岁女星隐婚生女!女方正面回应了男星胡歌即将迎来40岁生日,仍是单身状态的他近期狂被外界疯传已秘密与小6岁的女星王晓晨隐婚,甚至育有一名女儿。对此,王晓晨罕见正面回应了!胡歌近年来对感情生活相当低调,至今对外仍是39岁金莎公开恋情,保剑锋送祝福,曾合作十八岁的天空终于听到大美女金莎的恋情了!8月31日,金莎在社交平台上发文晒幸福,并公开恋情爱就是一起做好多的饭。金莎晒出了很多好吃的饭菜,中间还有两人用手比划爱心的照片,看上去简单而温馨,网友今晚开播!又有4部大剧来袭,聚焦热门题材,阵容不错该追哪部?整个八月的电视剧市场是精彩不断,并且各种题材的都有,有律政剧玫瑰之战,还有刑侦剧冰雨火罚罪等,当然还有古装大剧星汉灿烂的热播,几乎每一部都是爆款。而临近八月的尾巴,又有四部新剧来袭48岁王艳在豪宅顶楼看风景,皮肤白皙显年轻,穿一身白衣气质优雅王艳是内地著名的女演员,毕业于北京舞蹈学院,是科班出身。18岁出演电视剧梅花烙而进入演艺圈,在娱乐圈摸爬滚打多年获得了一定的成就。因其靓丽的外形和精湛的演技成为不少宅男的梦中情人。4次拒绝琼瑶,从古装王子到边缘演员,黄海冰可曾后悔过?时间退回到1997年,摆在26岁黄海冰眼前的,有两个不错的机会。一个是快乐大本营的主持人,另一个是出演还珠格格里的尔康。可是,面对两个绝佳的机会,黄海冰都婉拒了。之后,琼瑶并不甘心时隔6年王宝强神情自若,前经纪人被曝出狱回村喂猪,不复合吗?要说到王宝强,大家是否还会想起他的前妻马蓉和前经纪人宋喆的事情呢?从王宝强近日的状态来看,王宝强如今已经走出阴霾,而且感觉成长了很多,自从和前妻马蓉离婚后,王宝强专心忙于自己的事业欢乐颂3拒做扶弟魔的朱喆,她的事不关己是被逼的文竹英在欢乐颂3中22楼合租房中的朱喆和前面两季的樊胜美的家庭相似,都有一个专门压榨她们的家人。不同的是樊胜美一直做扶弟魔,最后弄得自己人到中年不仅仅嫁不出去,还没有存款。而朱喆三容祖儿张翰太甜,连生孩子环游世界想法都一致,网友原地结婚容祖儿张翰太甜牧野家族播出已经7期,最新一期中节目组打乱了陈容重新组合。任务卡留在原来的房间,人员重新调动。吴永恩和王子文这对情侣分开住,张翰和容祖儿则组成新的组合住进原先王子文和从人人喜爱嘎子到被爆轻生跳楼,33岁的谢孟伟都经历了什么?小时了了,大未必佳其实是娱乐圈中很多童星的现状。在这个像潮水一样风起云涌的娱乐圈,潮起又潮落,有人大红大紫,也会有人迅速消寂。都说人红是非多,但是做明星最怕的就是不红。就像他一样。王劲松凭冰雨火再出圈,不仅被称为定海神针,还带火一句台词由陈晓王一博王劲松领衔主演的缉毒剧冰雨火越看越上头,随着剧情的深入,不仅收视率频创新高,而且一集比一集高能。案件与人物走向的错综复杂,如草蛇灰线伏脉千里!悬念丛生,反转不断的剧情不
附睾炎,阴囊肿痛不舒,从枢机不利论,以和解少阳为法,其患告愈临床常将附睾炎分为急性和慢性,急性附睾炎病势大多较急,可见阴囊局限性疼痛附睾肿大周身不适。慢性附睾炎可见阴囊坠胀不适疼痛等症,亦有许多患者并无自觉不适,而是偶然或孕前检查发现附睾肿慢性咽炎,口里有痰吐不出?送你一剂祛痰方燥湿化痰帮你清嗓润喉大家好,我是刘医生。现在很多人都有慢性咽炎,也没有什么严重的病变,就是感觉喉咙里面有个异物,吐也吐不出去,咽也咽不进来。有时候感觉也不一定是有个异物,因为我们平时吃饭什么也不影响,咽炎和胃病的关系咽炎症状,早上恶性,刷牙想吐,感觉喉咙有东西,吐不出来,也不下去。使劲咳嗽可能有一点点痰。这就是咽炎很多朋友因为咽炎吃尽了各种药不好使。什么含片,抗生素,清火药等等。咽炎诊断不困难功能障碍严重,久治不愈?病很简单,复杂的是人心导语功能障碍严重,久治不愈?病很简单,复杂的是人心有不少朋友总是问我,为什么对于男性隐疾总是好不了,不论怎样去补总是感觉作用不大,不仅仅浪费了很多金钱,同样是浪费了很多的青春。其实二十大代表航天型号产品咽喉主刀师阎敏创新离我们每个人都不远中国经济周刊记者贾璇北京报道党的二十大报告中,习近平总书记强调加快建设制造强国质量强国航天强国交通强国网络强国数字中国,并为载人航天探月探火卫星导航等航天领域的创新点赞,让广大中国嗓子总是痒,一痒就咳嗽,橘皮加一物搞定慢性咽炎嗓子总是痒,一痒就咳嗽,有时候还会咽干咽痛,有异物感,早晨起来刷牙,容易出现恶心呕吐,有时候还会有胸闷痰多的情况。点我看舌象这是怎么回事,又该怎么办呢?大家好我是中医朱大夫,如果你心火胃火肝火身体会有哪些异常?少吃2物可降火在西医看来,上火与机体免疫功能失调后导致的局部感染应激状态下机体内环境失衡以及能量代谢等相关。目前主要认为上火是炎症感染蛋白质分解异常以及应激等几种假设。01hr什么是心火?心火是入秋身体干燥起皮,还长小疙瘩!教你1招有效焕肤秋冬季节,大家最烦的就是无处不在的干燥!特别是洗完澡后,皮肤不但紧绷发痒,轻轻一挠还有雪花般的皮屑飘下来。要想缓解身体肌肤的干燥,最管用的办法就是擦身体乳啦!今天小薇就来给大家推荐一到秋天,眼睛总干痒?眼科医生教你这五招,让眼睛不再干燥一到秋天,眼睛总是干痒,有烧灼感。每天起床都会觉得眼睛干磨,洗脸后眼睛特别红。看手机十几分钟,眼睛就会胀痛流泪,很不舒服。最近一段时间,因眼睛不适到眼科就诊的患者激增,经医生诊断,秋燥易上火!建议少吃热发物,多吃5样,滋阴润燥好度金秋说起秋天,大家都会用秋高气爽万物丰收一片金黄等形容词来修饰它。其实,秋天哪儿哪儿都好,唯独一点不好,就是太燥了。而且,这种干燥只依靠喝水还降不下去,这时候我们就可以从饮食上着手,多中国探索二号科考船及深海勇士载人潜水器获多项新突破中新网北京10月27日电(记者孙自法)中国科学院(中科院)27日向媒体发布信息说,在该院所属多家机构共同参与实施的探索二号科考船携深海勇士号载人潜水器最新航次任务中,科研人员顺利完