Spring启动类源码学习小记

现在面试Java 的,都必备SpringBoot了,一说SpringBoot,面试官又喜欢问底层,我也是这种形式主义的受害者之一,但是还别说,自从看了底层源码,心中大致上也有个了解,再碰到出问题的时候,解决起来也是比较轻松,所以说,虽然增删改改用不上,但是对于自己未来的发展还是非常有帮助的。
先随便看一个SpringBoot的启动类。可以看到最主要的就是一个run方法,理所当然点击进去看。

在这里插入图片描述

继续点击进去run

在这里插入图片描述

它在这一层new了一个SpringApplication并且又调用run,那就陪着它run进去看看。

在这里插入图片描述

在这里,内容终于开始重要了起来,那些读取配置信息,做监听,异常容器初始化,启动停止的监听器,读取自定义banner,打印banner之类的杂七杂八方法不重要,这里create了一个ApplicationContext,并且有调用了一个refresh() 方法,这个就很重要,容器的初始化和Bean的创建都会在那里面。点进去refreshContext()方法。

在这里插入图片描述

看到了面试官最喜欢问你的refresh()方法本体~

在这里插入图片描述

一路refresh()火花带闪电点进去,看到这里,就是SpringBoot容器初始化最底层的地块了。

(1)prepareRefresh()方法:
这是一个创建容器前的刷新预处理方法。执行到这里,等于宣布要启动一个SpringBoot项目了,要动工创建Bean工厂和创建父子容器之类的了
在这里插入图片描述
在这里插入图片描述
1:initPropertySources():初始化配置和属性设置,子类自定义个性化的属性方法等等。

2:校验属性的合法性,它会抛出一个什么“MissingRequiredProperties”的异常,也就是你参数缺失了,或者有错误的,都会在这里抛出来,更详细的去看这个接口的实现类源码去背书吧~”
3.earlyApplicationEvents是一个链式的HashSet集合类,是用来保存一些初始化早期产生的事件监听和object的。
(2)obtainFreshBeanFactory:初始化获取一个BeanFactory
在这里插入图片描述
(3)prepareBeanFactory:这个方法就是把上一步创建出来的Beanfactory又传进去了,传进去了做一些准备工作和基础的设置。进去看看~
点进去看发现真的非常的恶心,简单点总结以下:主要干了蛇么:
1:设置BeanFactory的类加载器(setBeanClassLoader),因为是Bean工厂,怎么加载类之类的讲究,还有表达式解析器。
2:添加一部分后置处理器(addBeanPostProcessor),就是加载一些类之前要做什么,以怎样的形式加载,解决一些循环依赖的问题。
3:设置忽略的自动装配的接口(ignoreDependency),忽略一些不必要的。
4:注册可以解析的自动装配(registerResolvableDependency),这样就可以在任何组件中自动注入Bean,例如在BeanFactory中,ApplicationContext中,ResourceLoader中等等。
5:添加后置处理器(BeanPostProcessor)。
6:添加编译时的AspectJ,代理模式的切面。这个切面在初始化和后置处理器中也是经常使用,通常是循环执行完一堆前置方法,才到目标方法,又执行一堆的后置方法,超级啰嗦,看得很乏困。
7:给BeanFactory注册Environment,SystemPropertiew等等一些用到的组件。
在这里插入图片描述
(4)postProcessBeanFactory:Bean工厂做完了准备工作后进行后置处理工作在这里插入图片描述
子类可以通过重写这个方法,实现在初始化创建BeanFactory完成后做一些自己进一步的Diy设置。
(5)invokeBeanFactoryPostProcessors,registerBeanPostProcessors:这两个方法很啰嗦,就是一堆后置处理器,先执行BeanDefinitionRegistry定义的方法,通过优先级先后执行注册,也就是把BeanPostProcessor添加到bean工厂中,其中有个Ordered顺序接口规定了先执行哪些,再执行哪些方法,执行完有序有优先级的,再执行无需无优先级的BeanDefinitionRegistryPostProcessors…这里给我的感觉,就像是剥洋葱一样,一层层的剥开,看了一眼洋葱的心后,又一层一层包裹起来。
不剥开外面那层,别想着到里面那层的方法。在这里插入图片描述
(6)initMessageSource:这个其实是通过MessageSource组件实现消息绑定,消息解析的国际化功能,通过国际化配置文件的key对应的value,按照区域信息获取,并且把获取到的信息创建好一个MessageSource放入BeanFactory中,再要用到国际化配置文件的值时候就可以自动注入了。
在这里插入图片描述
(7)初始化事件派发器,并且将ApplicationEventMulticaster添加到BeanFactory中,方便自动注入。
在这里插入图片描述
(8)registerListeners:用迭代器模式将所有ApplicationListener注册到事件派发器中。
ApplicationListener是事件监听ApplicationEvent的,是ApplicationContext事件机制中的一环节。通过它可以监听对应事件发生,从而进行某种自定义的操作。
在这里插入图片描述
(9)finishBeanFactoryInitialization:初始化剩下的所有单实例Bean。获取容器中所有的Bean进行初始化和创建对象。首先获取定义信息,RootBeanDefinition,通过懒加载,单实例的方式。
判断是否工厂Bean,是否实现工厂Bean接口的Bean,如果都不是,就去缓存中找是否已经有该Bean存在,没有的话,调用工厂模式著名的getBean(beanName);反射机制进行创建对象,创建前又会获取当前Bean是否依赖其他的Bean,如果有,就先getBean(beanName)先创建依赖的Bean,再创建目标Bean,再放回缓存中,再标志一下当前Bean已经被创建。
这里又会有一堆的BeanPostProcessorsAfterInitialIzation,顾名思义初始化前要做的事情,初始化后要做的又是一堆事情。判断是否自定义初始化方法,注册Bean的销毁方法,创建出来后把Bean放在单实例Bean缓存中(singletonObject)。
这么一通折腾下来,就算是初始化好了,这就是我们看到的banner图打印,跟着一大堆log,然后初始化一堆的Bean放入BeanFactory,然后假如没加注解,但是又在另外一个地方@Autowired或者@Resource的话,SpringBoot就找不到对应的依赖Bean放入IOC容器中,这里说的容器,其实就都是Map,通过Key(类名,全限定类名)Value(单例模式创建好的Bean存放在内存的地址,对象类型,存的是引用)。

以上是我个人学习后的总结,如果有说错的地方希望一起讨论哈~
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章