- 根据问题1,Spring 的Bean是怎么产生的?
先提出些问题?
1、Spring 的Bean是怎么产生的?
2、它的生命周期是如何的?
3、Spring的Bean是如何解决循环依赖的?
用xml配置的
<!--循环依赖问题-->
<bean id="instanceA" class="com.lagou.edu.InstanceA">
<property name="InstanceB" ref="instanceB"/>
</bean>
<bean id="instanceB" class="com.lagou.edu.InstanceB">
<property name="InstanceA" ref="instanceA"/>
</bean>
根据问题1,Spring 的Bean是怎么产生的?
1
2
3、接下来就是要看产生bean的逻辑代码
4
5
6
7
8
9
10
11
12
13
14
15
16
17
——————————————————————
》》》》》》》》》》》》》》》》》》》》》》》》》
其实可以看看new NamedBeanHolder()方法里面,发现里面传入xml的id,也就是beanName,
还有就是bean实例。那么现在就需要去找这两个东西才能进行赋值哦。
18
———————————————————————————-
》》》》》》》》》》》》》》》》》》》》》》》》》
19
20
21
其实第一次是先从缓存取getSingleton(beanName),如果取不到才去创建的。
22
23
24
这里是先从一级缓存中取,如果一级缓存没有就从二级缓存获取,如果二级也空,
但是缓存工厂(三级缓存)不为空,就从缓存工厂(三级缓存)中取,并将其从三级缓存删除,取到级二缓存中
25
一路走完,到单例缓存池获取的时候,进来就能拿到了(里面有三层判断),为什么能拿到呢,谁放的呢?
能从单例缓存池中拿,那么就有放,取存守恒原则,能取就有放,那么肯定有地方put进去
全局搜索singletonObjects.put,并在此处打断点,通过debug模式看他什么时候放进去的。
再通过左下角的调用栈,反推它是从哪里调进来的。具体步骤如下:
其实发现,put进去时候,也从二三级缓存删除了。
26
点进去addSingleton,并添加过滤条件。重启debug进来。
27
28
看看怎么放到一级缓存
29查看具体的调用栈
可以根据调用栈的信息,点进去看。
》》》》》》》》》》》》》》》》》》》》
30
31
32
====================》》》》》》》》》》》》》》》》》
33
34
35
====================》》》》》》》》》》》》》》》》》
36
37
结合刚刚通过调用栈进行反推,晓得
finishBeanFactoryInitialization 调用后是 ,preInstantiateSingletons又有调用
这里面是真正实例化Bean的逻辑
38
配合调用栈进行反推,晓得
preInstantiateSingletons调用后是 ,又有调用getBean()的
但是preInstantiateSingletons方法里面有调用getBean()的有好几个呢(可以先走流程,然后通过调用栈看是调用哪个具体的getBean())
39
40
41
42
当流程走完,发现sharedInstance = getSingleton(beanName, () -> {这行代码有返回实例
43
44
而且这些也需要有返回值哦,进入同样得先走完流程,看有返回值的那行代码
45
46
47
48
在这里就得到了问题一的答案了,
Spring 的Bean是在doCreateBean方法中调用了无参构造初始化了Bean对象。
这个方法里面也是解决依赖的关键。
49
50如何通过构造方法创建实例Bean
创建实例BeanA剖析开始
===================》start
51
52
第一次是先获取instantiationStrategy,然后调用instantiate方法。
53
54
进入是先有isKotlinReflectPresent返回,再进入。就会去调用无参构造了
55
56
57
创建实例BeanA剖析结束
====================》》》》》》》》》》》end
58拿到实例Bean后都干啥呢?
59
60
61
62
63
64
65
66
67
68
69
70
71
72
其实这个方法一开始是从单例缓存池拿不到的,它是一个未成熟的Bean,
把无参构造创建出来实例Bean放入三级缓存。(A之前已经放过咯,现在放B咯)
73通过构造方法创建实例BeanB并填充属性开始
74
75
76
77
78
79
80
81
82
83得到实例BeanA就一直返回。
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
==============================
注意:前置、后置方法都是进行遍历的。
org.springframework.context.support.AbstractApplicationContext#refresh
org.springframework.context.support.AbstractApplicationContext#finishBeanFactoryInitialization
org.springframework.beans.factory.config.ConfigurableListableBeanFactory#preInstantiateSingletons
org.springframework.beans.factory.support.AbstractBeanFactory#getBean
org.springframework.beans.factory.support.AbstractBeanFactory#doGetBean
org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#getSingleton
org/springframework/beans/factory/support/DefaultSingletonBeanRegistry.java:238
org.springframework.beans.factory.support.AbstractBeanFactory#createBean
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#doCreateBean
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#populateBean
org.springframework.beans.factory.support.AbstractBeanFactory#createBean
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#doCreateBean
……..
这是因为创建A的过程中,发现它依赖于B,所以它要去创建B,重复刚刚A走过的步骤
但是有个疑问?它点进去的方法怎么找不到呢?
注意:借鉴物理的质量守恒原则,可以有一个取存守恒原则,有取就有存,有get就有put。
那么在哪里给它put进去了呢?哪里创建的呢?(逆向思维,反向工程)