做一个合格的程序猿之浅析Spring IoC源码(十一)Spring refresh()方法解析后记1

扫码关注公众号:Java 技术驿站

发送:vip
将链接复制到本浏览器,永久解锁本站全部文章

【公众号:Java 技术驿站】 【加作者微信交流技术,拉技术群】
免费领取 2000+ 道 Java 面试题

上次分析refresh这块spring IoC的时候,时间比较仓促,只是debug了部分源码,大家分析起来不是很好~

今天我们还是先总结一下吧~

spring在实例化bean的时候,根据bean实现的接口不同,bean的实例化也是有先后顺序的

由于此块代码太多,贴图给大家的学习的效果不好,现在以spring 3.2.5源代码为例,大家再一份“温故”一下,然后“知新”

①:打开AbstractApplicationContext.java中refresh()先初始化好beanFactory(DefaultListableBeanFactory.java)【第445行~第496行】:

20191123100265\_1.png

这边先对beanFactory做好初始化,关于beanFactory的初始化前面已经讲过了,链接如下:

http://blog.csdn.net/linuu/article/details/50829981

②初始化好了beanfactory之后,就先开始处理实现BeanFactoryPostProcessor.java的bean,说明BeanFactoryPostProcessor的实例化的优先级最高

20191123100265\_2.png

2.1 原因:实现了BeanFactoryPostProcessor.java这个接口的bean需要具体的实现BeanFactoryPostProcessor中定义的接口postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory)这个接口。

而这个接口可以直接修改beanDefinitionMap中beanDefinition中保存的bean的信息,而beanDefinition是所有bean初始化的依据,也就是说所有bean依赖于beanDefinition,所以实现BeanFactoryPostProcessor的接口的bean优先初始化,这样如果该bean修改了其他bean的beanDefinition,其他bean在后面初始化的时候才能按照用户给的正确参数实例化,例如org.springframework.beans.factory.config.PropertyPlaceholderConfigurer这个类(该类具体作用参照链接:http://blog.csdn.net/linuu/article/details/50853687

2.2 如果打开461行的代码,你会发现,如果有多个bean实现了BeanFactoryPostProcessor接口,那么这些bean的初始化顺序也是有讲究的

AbstractApplicationContext.java 【605行~685行中】

2.2.1首先实例化的是实现BeanDefinitionRegistryPostProcessor这个接口的bean(很好理解,看字面就知道,这个接口要修改的就是BeanDefinition,不先正确的实例化好它,实例化好,因为这个也许是其他bean的依赖注入呢),官方注释

20191123100265\_3.png

(if any,说明了什么,说明了它比谁都的优先级都高)

2.2.2 接着看注释:

20191123100265\_4.png

接着按照字面的理解,同样,如果多个bean实现了BeanFactoryPostProcessor的情况下,谁实现了PriorityOrdered接口,谁也是优先执行,当然在实现BeanDefinitionRegistryPostProcessor这个之后

然后是实现了Ordered.java的接口,最后就是没有实现这2个特殊接口的普通实现BeanFactoryPostProcessor的bean了

20191123100265\_5.png

2.3 实现了BeanFactoryPostProcessor这个接口的bean,实例化的时候,第一件事情就是先把自己实例化,把自己实例化后才可以去做实现BeanFactoryPostProcessor这个接口定义的事情,这就是为什么下图中①模块比②模块先打印的原因了:

20191123100265\_6.png

③ 现在我们开始分析上图中①的执行顺序,首先①模块执行的入口是

20191123100265\_7.png

追踪getBean这个方法,我们会追踪到AbstractBeanFactory.java 的第230行doGetBean()这个方法

这块代码的执行顺序是:

3.1 首先先去实例化好的bean中去找,如果找到,直接返回【234行~250行】

3.2 然后去当前beanfactory中父类factory找,如果能找到父类的factory,则叫父类去返回,(与jvm的classloader的双亲加载比较像~)【260行~272行】

3.3 如果都没有找到,则开始初次实例化,先标记开始实例化【274~276行】

3.4 开始查看当前要实例化的bean是否依赖于其他的bean,如果依赖,则先实例化依赖的bean,如果依赖的bean还依赖于其他的bean,则接着递归创建

3.5如果创建的bean是单例(spring默认单例)接着创建

20191123100265\_8.png

打开createBean,一直追踪到AbstractAutowireCapableBeanFactory.java的1030行,此时已经对该bean在spring的名片beandefinition中的class已经做了初步的校验,例如该类是否是private是否是abstract是否有默认的构造函数等等,符合校验后直接根据java的反射进行创建(当然此类不是接口),创建的对象经过spring包装返回一个BeanWrapper

因为此时bean已经创建了,所以下图中红色框框已经打印出来:

20191123100265\_9.png

我们接着看AbstractAutowireCapableBeanFactory.java这个方法的第480行doCreateBean()这个方法的

20191123100265\_10.png

此时我们已经创建好了bean了,我们要做的事还有Setter值,beanNameAware beanFactoryAware,initMethod(这些前几篇博客有介绍)这些创建后的“动作”

好的,接着看519行:populateBean这个方法(开始setter值)

20191123100265\_11.png

因为setter可以根据多个属性setter注入,我们这边就不分析了,我们追踪到AbstractAutowireCapableBeanFactory.java的1368行applyPropertyValues这边的代码块

setter好后,执行521行代码,进入initializeBean这个方法

20191123100265\_12.png

这个方法一开始if else都要执行invokeAwareMethods这个方法,对Aware我们很熟悉,进入查看

20191123100265\_13.png

是的,首先执行实现BeanNameAware接口的setBeanName方法,然后是实现BeanClassLoaderAware的setBeanClassLoader方法,最后是实现BeanFactoryAware这个bean的方法

好了,跟我们打印的顺序是一致的:

20191123100265\_14.png

我们接着看initializeBean这个方法

20191123100265\_15.png

BeanPostProcessor需要注册才能运行,这边暂不分析,所以先看1509行代码invokeInitMethods,进入看:

20191123100265\_16.png

如果该bean实现了InitializingBean接口,则先执行afterPropertiesSet()方法,最后

20191123100265\_17.png

最后执行了我们在spring-init.xml中自定义的

20191123100265\_18.png

所以最后打印了:

20191123100265\_19.png

如上图中①模块所示,关于②模块下次再解析,这篇主要是对上篇日记的补充,不好意思,上次解析太多粗糙了,希望这篇对大家有帮助,END~


来源:http://ddrv.cn/a/88268

赞(0) 打赏
版权归原创作者所有,任何形式的转载请联系博主:daming_90:Java 技术驿站 » 做一个合格的程序猿之浅析Spring IoC源码(十一)Spring refresh()方法解析后记1

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏