SpringBoot项目启动过程源码终于整体捋了一遍(七)

上篇看了一部分的run()方法,先贴一下run()方法:

上篇看到了listeners.starting();介绍了SpringBoot启动时的事件发布机制,并且遗留了一个问题,即初始化SpringApplication时设置初始化器setInitializers()有什么用,这篇继续往下看:

利用参数args构建了一个DefaultApplicationArguments对象,顾名思义应该是应用参数,用到了args这个得好好看看:

可以看到args是被设置为它的属性,并且有一个getSourceArgs()方法可以拿到,那后面如果有地方调用这个方法得留点心,说不定可以知道args和java -jar的参数有什么联系。

继续往下看:

这里是用刚刚的应用参数DefaultApplicationArguments对象和前面拿到的SpringApplicationRunListeners监听流水线去拿一个可配置的环境ConfigurableEnvironment对象,看样子是配置环境的时候又得去发布点事件让某些应用监听干活啊,看一下这个prepareEnvironment()方法,里面就是去配置环境参数了:

上来先是创建了一个ConfigurableEnvironment对象,getOrCreateEnvironment()方法就不贴了,里面分应用类型是SERVLET还是REACTIVE创建不同的环境变量对象,依据就是初始化SpringApplication时推断出来的应用类型,这个第三篇提到过(https://blog.csdn.net/weixin_42447959/article/details/105055832)。然后看一下configureEnvironment()方法,这个方法开始配置环境:

this.addConversionService除非调用其set方法改为false,不然默认就是true。这个ConversionService是Spring中用于运行时类型转换的类,它可以将变量在字符串,数字,枚举,集合,映射和其他常见类型之间进行转换,这是一个接口,当然也就可以实现里面的方法自定义转换规则,可以看一下这个getSharedInstance():

典型的单例模式,看来类型转换器只需要一个,一般这种什么什么shared的方法里面都是单例,ApplicationConversionService是ConversionService接口的实现类,可以去看一下,平时如果需要自定义类型转换规则的地方可以学起来,这里拿到转换器后也是用setConversionService()方法设置进了ConfigurableEnvironment环境对象,继续往下看这个configurePropertySources()方法:

 哈!一眼就看到了到处都是commandLine命令行字样,最初的疑问终于要找到答案了,这个方法是去拿环境中的配置属性资源,配置属性无非来自配置文件和命令行嘛,这里是将配置文件里的配置属性addLast()添加在后面,后面又将命令行中的配置属性addFirst添加在前面,那这可以理解为命令行中的配置优先级比较高吗?想想好像确实是这样,比如在yml配置文件中配置spring.profiles.active=dev,然后java -jar的时候加启动参数--spring.profiles.active=prod,最后生效的配置文件还是prod生产环境的。其他的图不贴了,有兴趣的可以去看一看,贴一下怎么利用命令行参数args去初始化SimpleCommandLinePropertySource命令行属性资源对象的:

就这?那就看一下parse()方法:

终于找到答案了,java -jar后面的启动参数字符串就是在这里被解析为配置的,怪不得参数要用"--"开头。

刚看的configurePropertySources()方法是拿到配置属性资源,主要有两个来源即配置文件和命令行,继续往下看configureProfiles()方法:

这个方法的注释写的很明白,即"为这个应用程序配置哪些配置文件是活动的(默认情况下是活动的)",也就是激活哪些配置文件,上一个方法可能是拿到了一大堆配置文件,这个方法就是真正决定哪些配置有效了,这个getActiveProfiles()方法最终是调用了doGetActiveProfiles(),大佬惯用的手法,直接看这个方法:

 看这个ACTIVE_PROFILES_PROPERTY_NAME常量:

根据这个key拿到了值,之后的事不看源码也能知道怎么回事了,到这里就真相大白了。 

这一顿扯的有点远,继续回到prepareEnvironment()方法,再贴一遍这个方法:

刚刚是看完了configureEnvironment()方法,总结一下就是给环境对象ConfigurableEnvironment喂地肥肥的,给了他类型转化器,最主要的还是把一堆配置加入环境对象中,方法名配置环境嘛,应该的。

继续往下看:

很熟悉吧,这个上篇分析过了(https://blog.csdn.net/weixin_42447959/article/details/105111675),最终是事件分发器发布了ApplicationEnvironmentPreparedEvent应用环境准备事件,bean容器中对应的ApplicationListener监听到了以后会去执行自己的逻辑,具体哪些监听器监听到了,打了一下断点是这些:

当然里面部分不是spring框架中的,例如PuristBootBanner就是自定义的监听器,具体这些监听干了什么有时间再仔细看看。

回到文章开头的run()方法中继续往下看这行:

现在的environment今非昔比了,环境中有一大堆配置了,看一下这个方法要干嘛:

这里又是大佬惯用的一个手法,先System.getProperty(),再System.setProperty(),也是以防万一吧,看一下这个属性的键是哪个:

上面那段代码把这个属性设置为true,好像很少在配置文件中写"spring.beaninfo.ignore"这个配置,也是看了上面的一大堆注释,这个属性作用于是否跳过对BeanInfo类的搜索,注解中说如果改为true即开启之后会减少应用启动和加载的开销。首先这个BeanInfo类顾名思义可以拿到bean容器中的bean信息,用法如图:

 但是这个注释中说默认为false是考虑到所有的BeanInfo元数据类?不懂,感觉是应该设置为true,这里SpringBoot启动的时候,除非在配置文件中配置false,也是默认把这里设置为true,也是为了减小不必要的开销吧。

回到文章开头的run()方法中继续往下看这行:

这就是启动Spring的时候那个大大的Spring图案打印的方法,看一下这个方法:

 可以看出是否打启动Banner有一个this.bannerMode控制,项目中如果需要打印自定义的Banner,就需要将这个布尔型变量设置为false,然后自定义一个ApplicationListener去打印自定义Banner。

这篇就到这里吧,在run()方法中就走了两行代码,主要分析了启动过程中如何将配置属性加入环境对象中,总之是把ConfigurableEnvironment这个对象喂地肥肥的,告诉了它不少东西。这篇最大的收获还是找到了最初的问题答案,即args和java -jar后面的启动参数有什么关系,就是在给环境对象配置属性的时候用到了。同时文章开头的问题依然遗留着,即初始化SpringApplication时设置初始化器setInitializers()有什么用,遗留了好几篇了,不过之后终归会找到答案的吧。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值