終于拿到offer了窑睁,但是還是想試試下周幾家大公司挺峡,努力準(zhǔn)備吧,不可懈档Eァ橱赠!
那什么是依賴注入呢?
所謂依賴注入,就是由IOC容器在運行期間箫津,動態(tài)地將某種依賴關(guān)系注入到對象之中病线。再完成IOC容器初始化之后,也就是所謂的Bean加載完成后鲤嫡,我們需要對這些Bean進行調(diào)用和獲取送挑,這個過程就叫依賴注入。
那什么時候會觸發(fā)依賴注入呢?
- 通過getBean()方法獲取Bean對象暖眼。
- 給Bean配置了懶加載惕耕,ApplicationContext啟動完成后調(diào)用getBean()來實例化對象。
現(xiàn)在計算機性能已經(jīng)足夠诫肠,不是特殊要求下盡量別做懶加載司澎,這樣的話可以減少web運行時的調(diào)用時間開銷。
好了栋豫,介紹完這些就開始我們的DI之旅挤安。
1. BeanFactory
通過Spring獲取Bean的最根本的接口。
|
<pre class="prettyprint linenums" style="box-sizing: border-box; background: rgb(231, 229, 220) !important; border: none !important; margin: 0px !important; width: auto !important; float: none !important; clear: none !important; overflow: visible !important; font-family: "Open Sans", "Hiragino Sans GB", "Microsoft YaHei", "WenQuanYi Micro Hei", Arial, Verdana, Tahoma, sans-serif !important; font-size: 14px !important; line-height: 24px !important; padding: 0px 5px !important; white-space: pre !important; box-shadow: rgba(0, 0, 0, 0) 0px 0px 0px !important; border-radius: 0px !important; color: rgb(92, 92, 92) !important; text-align: right !important; min-width: 28px !important;">1
2
3
4
5
6
7
8
9
10
11
12
13
14
</pre>
|
<pre class="java5 prettyprint linenums" style="box-sizing: border-box; background: transparent !important; border: none !important; margin: 0px !important; width: auto !important; float: none !important; clear: none !important; overflow: visible !important; font-family: monospace; font-size: 14px !important; line-height: 24px !important; padding: 0px 5px !important; white-space: pre !important; box-shadow: rgba(0, 0, 0, 0) 0px 0px 0px !important; border-radius: 0px !important;">// 如果myJndiObject時FactoryBean丧鸯, 則 &myJndiObject 將返回工廠而不是返回實例蛤铜。
String FACTORY_BEAN_PREFIX = "&";
// 獲取bean實例
Object getBean(String name) throws BeansException;
// 判斷一個bean是否時單例
boolean isSingleton(String name) throws NoSuchBeanDefinitionException;
// 判斷一個bean是否是原型
boolean isPrototype(String name) throws NoSuchBeanDefinitionException;
// 檢查bean的name和type是否匹配
boolean isTypeMatch(String name, Class targetType) throws NoSuchBeanDefinitionException;
// 獲取bean類型
Class<?> getType(String name) throws NoSuchBeanDefinitionException;
// 獲取bean別名
String[] getAliases(String name);</pre>
|
getBean()方法有很多重載方法,上面只總結(jié)了一個丛肢。這個方法是DI的入口方法围肥,接下來會從這個方法開始往下研究。
2. AbstractBeanFactory
從名字也能看出蜂怎,這是BeanFactory的抽象實現(xiàn)類穆刻。
|
<pre class="prettyprint linenums" style="box-sizing: border-box; background: rgb(231, 229, 220) !important; border: none !important; margin: 0px !important; width: auto !important; float: none !important; clear: none !important; overflow: visible !important; font-family: "Open Sans", "Hiragino Sans GB", "Microsoft YaHei", "WenQuanYi Micro Hei", Arial, Verdana, Tahoma, sans-serif !important; font-size: 14px !important; line-height: 24px !important; padding: 0px 5px !important; white-space: pre !important; box-shadow: rgba(0, 0, 0, 0) 0px 0px 0px !important; border-radius: 0px !important; color: rgb(92, 92, 92) !important; text-align: right !important; min-width: 28px !important;">1
2
3
</pre>
|
<pre class="java5 prettyprint linenums" style="box-sizing: border-box; background: transparent !important; border: none !important; margin: 0px !important; width: auto !important; float: none !important; clear: none !important; overflow: visible !important; font-family: monospace; font-size: 14px !important; line-height: 24px !important; padding: 0px 5px !important; white-space: pre !important; box-shadow: rgba(0, 0, 0, 0) 0px 0px 0px !important; border-radius: 0px !important;">public Object getBean(String name) throws BeansException {
return doGetBean(name, null, null, false);
}</pre>
|
doGetBean()方法也是該類中的方法。
|
<pre class="prettyprint linenums" style="box-sizing: border-box; background: rgb(231, 229, 220) !important; border: none !important; margin: 0px !important; width: auto !important; float: none !important; clear: none !important; overflow: visible !important; font-family: "Open Sans", "Hiragino Sans GB", "Microsoft YaHei", "WenQuanYi Micro Hei", Arial, Verdana, Tahoma, sans-serif !important; font-size: 14px !important; line-height: 24px !important; padding: 0px 5px !important; white-space: pre !important; box-shadow: rgba(0, 0, 0, 0) 0px 0px 0px !important; border-radius: 0px !important; color: rgb(92, 92, 92) !important; text-align: right !important; min-width: 28px !important;">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
</pre>
|
<pre class="java5 prettyprint linenums" style="box-sizing: border-box; background: transparent !important; border: none !important; margin: 0px !important; width: auto !important; float: none !important; clear: none !important; overflow: visible !important; font-family: monospace; font-size: 14px !important; line-height: 24px !important; padding: 0px 5px !important; white-space: pre !important; box-shadow: rgba(0, 0, 0, 0) 0px 0px 0px !important; border-radius: 0px !important;">// 依賴注入 從這里開始發(fā)生
private <T> T doGetBean(
final String name, final Class<T> requiredType, final Object[] args, boolean typeCheckOnly)
throws BeansException {
// 根據(jù)指定名字獲取被管理Bean的名稱
// 如果是別名杠步, 則轉(zhuǎn)換為真正的bean名
final String beanName = transformedBeanName(name);
Object bean;
// Eagerly check singleton cache for manually registered singletons.
// 先從緩存中取單例 bean
Object sharedInstance = getSingleton(beanName);
if (sharedInstance != null && args == null) {
if (logger.isDebugEnabled()) {
// 如果有氢伟,則直接返回該bean
if (isSingletonCurrentlyInCreation(beanName)) {
logger.debug("Returning eagerly cached instance of singleton bean '" + beanName +
"' that is not fully initialized yet - a consequence of a circular reference");
}
else {
logger.debug("Returning cached instance of singleton bean '" + beanName + "'");
}
}
//獲取 bean 的實例對象
bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
}
else {
// Fail if we're already creating this bean instance:
// We're assumably within a circular reference.
// 如果不是單例對象, 而且 緩存中有原型模式bean幽歼, 就拋異常
if (isPrototypeCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}
// 檢查 BeanDefinition 是否再當(dāng)前的factory中朵锣, 如果不在則委托父類容器取查找
// Check if bean definition exists in this factory.
BeanFactory parentBeanFactory = getParentBeanFactory();
if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
// Not found -> check parent.
String nameToLookup = originalBeanName(name);
if (args != null) {
// Delegation to parent with explicit args.
// 委托父類容器取找(名字+參數(shù))
return (T) parentBeanFactory.getBean(nameToLookup, args);
}
else {
// 委托父類容器取找(名稱+類型)
// No args -> delegate to standard getBean method.
return parentBeanFactory.getBean(nameToLookup, requiredType);
}
}
if (!typeCheckOnly) {
// 標(biāo)記 bean 被創(chuàng)建
markBeanAsCreated(beanName);
}
// 根據(jù)bean名稱獲取 父類的 beanDefinition, 合并繼承公共屬性
final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
checkMergedBeanDefinition(mbd, beanName, args);
// Guarantee initialization of beans that the current bean depends on.
// 獲取當(dāng)前bean 所有依賴Bean 的集合
String[] dependsOn = mbd.getDependsOn();
if (dependsOn != null) {
for (String dependsOnBean : dependsOn) {
// 遞歸調(diào)用试躏, 獲取當(dāng)前Bean的依賴Bean
getBean(dependsOnBean);
// 把依賴Bean注冊給當(dāng)前的Bean
registerDependentBean(dependsOnBean, beanName);
}
}
// Create bean instance.
// 創(chuàng)建bean 實例
if (mbd.isSingleton()) {
// 創(chuàng)建 bean 實例對象猪勇, 并且注冊給所依賴的對象
sharedInstance = getSingleton(beanName, new ObjectFactory() {
public Object getObject() throws BeansException {
try {
// 創(chuàng)建一個指定bean 實例對象
return createBean(beanName, mbd, args);
}
catch (BeansException ex) {
// Explicitly remove instance from singleton cache: It might have been put there
// eagerly by the creation process, to allow for circular reference resolution.
// Also remove any beans that received a temporary reference to the bean.
// 清除該單例
destroySingleton(beanName);
throw ex;
}
}
});
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
else if (mbd.isPrototype()) {
// It's a prototype -> create a new instance.
Object prototypeInstance = null;
try {
beforePrototypeCreation(beanName);
prototypeInstance = createBean(beanName, mbd, args);
}
finally {
afterPrototypeCreation(beanName);
}
bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
}
// 如果創(chuàng)建的bean 不是單例也不是原型设褐, 則根據(jù)聲明周期選擇實例化bean的方法
// 如 request session 等不同范圍的實例
else {
String scopeName = mbd.getScope();
final Scope scope = this.scopes.get(scopeName);
// 如果 scope 是空颠蕴, 則拋異常
if (scope == null) {
throw new IllegalStateException("No Scope registered for scope '" + scopeName + "'");
}
// 否則
try {
// 獲取一個指定了scope的bean實例
Object scopedInstance = scope.get(beanName, new ObjectFactory() {
public Object getObject() throws BeansException {
beforePrototypeCreation(beanName);
try {
return createBean(beanName, mbd, args);
}
finally {
afterPrototypeCreation(beanName);
}
}
});
bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
}
catch (IllegalStateException ex) {
throw new BeanCreationException(beanName,
"Scope '" + scopeName + "' is not active for the current thread; " +
"consider defining a scoped proxy for this bean if you intend to refer to it from a singleton",
ex);
}
}
}
// Check if required type matches the type of the actual bean instance.
// 檢查是否需要類型檢測
if (requiredType != null && bean != null && !requiredType.isAssignableFrom(bean.getClass())) {
throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
}
return (T) bean;
}</pre>
|
總結(jié)以下它都做了什么事情:
根據(jù)傳來的
bean
的name
(有可能是別名)來獲取真正的bean
名稱:beanName
泣刹。根據(jù)
beanName
獲取單例實例,如果有直接獲取到bean實例
并返回犀被,DI完成椅您。-
如果根據(jù)
beanName
沒有獲得到單例實例:3.1 判斷是不是原型實例,如果是寡键,則拋出創(chuàng)建失敗異常掀泳,如果不是,下一步西轩。
3.2 檢查
BeanDefinition
是否在當(dāng)前的容器中员舵,如果不在那可能在父類容器中,所以委托父類容器查找藕畔,如果還沒有马僻,則再上一級容器…遞歸查找。3.3 檢查這個實例是否是為了類型檢查而獲取注服,而不是用來使用韭邓,如果是,標(biāo)記這個bean已經(jīng)被創(chuàng)建溶弟,如果不是女淑,下一步。
3.4 根據(jù)
beanName
獲取父類的BeanDefinition
辜御,并檢查該對象類類型鸭你,比如不能是抽象類等。3.5 根據(jù)
beanName
獲取所有該bean
依賴的Bean集合
擒权,如果該集合有值苇本,則遍歷DI(遞歸調(diào)用getBean()
)該bean集合
里的bean,并把bean注冊給當(dāng)前的bean(維護了一個map
來存放關(guān)系)菜拓。3.6 如果3.4中獲取的
BeanDefinition
是單例瓣窄,則根據(jù)該單例對象和beanName
和args
創(chuàng)建一個實例對象;否則纳鼎,判斷BeanDefinition
是否是原型俺夕,如果是則根據(jù)beanName,
該對象,args
創(chuàng)建一個實例;否則拿到3.4獲取的BeanDefinition
對象的生命周期Scope
,然后根據(jù)scope
來創(chuàng)建實例對象贱鄙,參數(shù)(beanName,bd,args)
劝贸。3.7 檢查是否需要類型檢測
3.8 返回
3.1-3.7
生成的實例。
然后我們再看看 createBean()方法的實現(xiàn)逗宁。
|
<pre class="prettyprint linenums" style="box-sizing: border-box; background: rgb(231, 229, 220) !important; border: none !important; margin: 0px !important; width: auto !important; float: none !important; clear: none !important; overflow: visible !important; font-family: "Open Sans", "Hiragino Sans GB", "Microsoft YaHei", "WenQuanYi Micro Hei", Arial, Verdana, Tahoma, sans-serif !important; font-size: 14px !important; line-height: 24px !important; padding: 0px 5px !important; white-space: pre !important; box-shadow: rgba(0, 0, 0, 0) 0px 0px 0px !important; border-radius: 0px !important; color: rgb(92, 92, 92) !important; text-align: right !important; min-width: 28px !important;">1
2
</pre>
|
<pre class="java5 prettyprint linenums" style="box-sizing: border-box; background: transparent !important; border: none !important; margin: 0px !important; width: auto !important; float: none !important; clear: none !important; overflow: visible !important; font-family: monospace; font-size: 14px !important; line-height: 24px !important; padding: 0px 5px !important; white-space: pre !important; box-shadow: rgba(0, 0, 0, 0) 0px 0px 0px !important; border-radius: 0px !important;">protected abstract Object createBean(String beanName, RootBeanDefinition mbd, Object[] args)
throws BeanCreationException;</pre>
|
3. AbstractAutowireCapableBeanFactory.java
|
<pre class="prettyprint linenums" style="box-sizing: border-box; background: rgb(231, 229, 220) !important; border: none !important; margin: 0px !important; width: auto !important; float: none !important; clear: none !important; overflow: visible !important; font-family: "Open Sans", "Hiragino Sans GB", "Microsoft YaHei", "WenQuanYi Micro Hei", Arial, Verdana, Tahoma, sans-serif !important; font-size: 14px !important; line-height: 24px !important; padding: 0px 5px !important; white-space: pre !important; box-shadow: rgba(0, 0, 0, 0) 0px 0px 0px !important; border-radius: 0px !important; color: rgb(92, 92, 92) !important; text-align: right !important; min-width: 28px !important;">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
</pre>
|
<pre class="java5 prettyprint linenums" style="box-sizing: border-box; background: transparent !important; border: none !important; margin: 0px !important; width: auto !important; float: none !important; clear: none !important; overflow: visible !important; font-family: monospace; font-size: 14px !important; line-height: 24px !important; padding: 0px 5px !important; white-space: pre !important; box-shadow: rgba(0, 0, 0, 0) 0px 0px 0px !important; border-radius: 0px !important;">// 創(chuàng)建bean 實例
@Override
protected Object createBean(final String beanName, final RootBeanDefinition mbd, final Object[] args)
throws BeanCreationException {
if (logger.isDebugEnabled()) {
logger.debug("Creating instance of bean '" + beanName + "'");
}
// Make sure bean class is actually resolved at this point.
// 解析和確定 bean 可以實例化
resolveBeanClass(mbd, beanName);
// Prepare method overrides.
// 準(zhǔn)備方法覆蓋
try {
mbd.prepareMethodOverrides();
}
catch (BeanDefinitionValidationException ex) {
throw new BeanDefinitionStoreException(mbd.getResourceDescription(),
beanName, "Validation of method overrides failed", ex);
}
try {
// Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.
// 給 Bean處理器 一個機會映九, 返回一個目標(biāo)bean實例
Object bean = resolveBeforeInstantiation(beanName, mbd);
if (bean != null) {
return bean;
}
}
catch (Throwable ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"BeanPostProcessor before instantiation of bean failed", ex);
}
Object beanInstance = doCreateBean(beanName, mbd, args);
if (logger.isDebugEnabled()) {
logger.debug("Finished creating instance of bean '" + beanName + "'");
}
return beanInstance;
}</pre>
|
總結(jié)以下它都做了什么:
- 確定
beanName
和RootBeanDefinition
可以被實例化。 - 執(zhí)行方法覆蓋
- 看
BeanPostProcessors
能否再解析之前獲取到bean瞎颗,如果能則直接返回件甥,否則下一步捌议。 - 調(diào)用
doCreateBean()
方法,獲取bean
實例.
doCreateBean()
方法也是該類中的。
|
<pre class="prettyprint linenums" style="box-sizing: border-box; background: rgb(231, 229, 220) !important; border: none !important; margin: 0px !important; width: auto !important; float: none !important; clear: none !important; overflow: visible !important; font-family: "Open Sans", "Hiragino Sans GB", "Microsoft YaHei", "WenQuanYi Micro Hei", Arial, Verdana, Tahoma, sans-serif !important; font-size: 14px !important; line-height: 24px !important; padding: 0px 5px !important; white-space: pre !important; box-shadow: rgba(0, 0, 0, 0) 0px 0px 0px !important; border-radius: 0px !important; color: rgb(92, 92, 92) !important; text-align: right !important; min-width: 28px !important;">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
</pre>
|
<pre class="java5 prettyprint linenums" style="box-sizing: border-box; background: transparent !important; border: none !important; margin: 0px !important; width: auto !important; float: none !important; clear: none !important; overflow: visible !important; font-family: monospace; font-size: 14px !important; line-height: 24px !important; padding: 0px 5px !important; white-space: pre !important; box-shadow: rgba(0, 0, 0, 0) 0px 0px 0px !important; border-radius: 0px !important;">// 真正創(chuàng)建bean實例
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final Object[] args) {
// Instantiat|e the bean.
// 封裝bean
BeanWrapper instanceWrapper = null;
if (mbd.isSingleton()) {
// 如果是單例模式的bean,從容器中獲取同名bean
instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
}
// 如果沒有同名bean老充, 則創(chuàng)建bean實例
if (instanceWrapper == null) {
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
// 如果有同名bean圣絮, 則獲取到封裝實例
final Object bean = (instanceWrapper != null ? instanceWrapper.getWrappedInstance() : null);
// 獲取實例化對象類型
Class beanType = (instanceWrapper != null ? instanceWrapper.getWrappedClass() : null);
// Allow post-processors to modify the merged bean definition.
// 調(diào)用后置處理器
synchronized (mbd.postProcessingLock) {
if (!mbd.postProcessed) {
applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
mbd.postProcessed = true;
}
}
// Eagerly cache singletons to be able to resolve circular references
// even when triggered by lifecycle interfaces like BeanFactoryAware.
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
isSingletonCurrentlyInCreation(beanName));
if (earlySingletonExposure) {
if (logger.isDebugEnabled()) {
logger.debug("Eagerly caching bean '" + beanName +
"' to allow for resolving potential circular references");
}
addSingletonFactory(beanName, new ObjectFactory() {
public Object getObject() throws BeansException {
return getEarlyBeanReference(beanName, mbd, bean);
}
});
}
// Initialize the bean instance.
// bean對象初始化, 依賴注入開始,exposedObject就是完成后的bean
Object exposedObject = bean;
try {
// 將bean 實例封裝, 并且 bean 定義中配置的屬性值賦值給實例對象
populateBean(beanName, mbd, instanceWrapper);
// 初始化 bean對象
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
catch (Throwable ex) {
if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {
throw (BeanCreationException) ex;
}
else {
throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);
}
}
// 如果指定名稱bean已經(jīng)注冊單例模式
if (earlySingletonExposure) {
Object earlySingletonReference = getSingleton(beanName, false);
if (earlySingletonReference != null) {
if (exposedObject == bean) {
// 如果兩個對象相等, bean初始化完成
exposedObject = earlySingletonReference;
}
// 如果不相等粉怕, 則找出當(dāng)前bean的依賴bean
else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
String[] dependentBeans = getDependentBeans(beanName);
Set<String> actualDependentBeans = new LinkedHashSet<String>(dependentBeans.length);
for (String dependentBean : dependentBeans) {
// 檢查依賴bean (是否繼承接口,是否是父子關(guān)系抒巢。斋荞。)
if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
actualDependentBeans.add(dependentBean);
}
}
if (!actualDependentBeans.isEmpty()) {
throw new BeanCurrentlyInCreationException(beanName,
"Bean with name '" + beanName + "' has been injected into other beans [" +
StringUtils.collectionToCommaDelimitedString(actualDependentBeans) +
"] in its raw version as part of a circular reference, but has eventually been " +
"wrapped. This means that said other beans do not use the final version of the " +
"bean. This is often the result of over-eager type matching - consider using " +
"'getBeanNamesOfType' with the 'allowEagerInit' flag turned off, for example.");
}
}
}
}
// Register bean as disposable.
// 注冊完成依賴注入的bean
try {
registerDisposableBeanIfNecessary(beanName, bean, mbd);
}
catch (BeanDefinitionValidationException ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
}
return exposedObject;
}</pre>
|
同樣,總結(jié)以下它干的事情:
- 根據(jù)
beanName
獲取beanWrapper
對象虐秦。如果beanWrapper
對象是空平酿,則調(diào)用createBeanInstance()
方法創(chuàng)建bean
實例。否則悦陋,下一步 - 通過
beanWrapper
對象獲取bean實例和class
類型蜈彼。 - 允許
postProcessors
調(diào)整組合BeanDefinition
。 - 如果
RootBeanDefinition
是單例并且允許循環(huán)引用并且beanName
正在進行單例創(chuàng)建俺驶,將beanName
添加到單例工廠幸逆。 - 調(diào)用
populateBean()
方法給bean的屬性值賦值,然后初始化bean對象并返回創(chuàng)建的bean實例暮现,如果拋異常还绘,則下一步。 - 如果該
beanName
對象已經(jīng)注冊單例模式栖袋,則從單例中獲取拍顷,并判斷獲取到的bean實例(B
)與BeanWrapper
中的bean實例(A
)是同一個實例,如果是塘幅,則返回A
或者B
昔案,如果不是,則遞歸找出它的依賴bean
电媳。 - 返回
1-6
產(chǎn)生的bean
實例踏揣。
我們首次獲取bean實例的時候,bean工廠是肯定沒有的匾乓,所以我們首次獲取到的BeanWrapper應(yīng)該是空對象捞稿,但是它調(diào)用了createBeanInstance()
方法后,可以看到spring是很確定它能拿到對象,那么我們看看這個方法的實現(xiàn)娱局。它仍然是這個類中的方法彰亥。
|
<pre class="prettyprint linenums" style="box-sizing: border-box; background: rgb(231, 229, 220) !important; border: none !important; margin: 0px !important; width: auto !important; float: none !important; clear: none !important; overflow: visible !important; font-family: "Open Sans", "Hiragino Sans GB", "Microsoft YaHei", "WenQuanYi Micro Hei", Arial, Verdana, Tahoma, sans-serif !important; font-size: 14px !important; line-height: 24px !important; padding: 0px 5px !important; white-space: pre !important; box-shadow: rgba(0, 0, 0, 0) 0px 0px 0px !important; border-radius: 0px !important; color: rgb(92, 92, 92) !important; text-align: right !important; min-width: 28px !important;">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
</pre>
|
<pre class="java5 prettyprint linenums" style="box-sizing: border-box; background: transparent !important; border: none !important; margin: 0px !important; width: auto !important; float: none !important; clear: none !important; overflow: visible !important; font-family: monospace; font-size: 14px !important; line-height: 24px !important; padding: 0px 5px !important; white-space: pre !important; box-shadow: rgba(0, 0, 0, 0) 0px 0px 0px !important; border-radius: 0px !important;">protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, Object[] args) {
// Make sure bean class is actually resolved at this point.
// 確保bean可實例化(不能是抽象類等)
Class beanClass = resolveBeanClass(mbd, beanName);
// 如果這個bean 不是public 修飾符或者不被允許公共訪問, 拋出異常
if (beanClass != null && !Modifier.isPublic(beanClass.getModifiers()) && !mbd.isNonPublicAccessAllowed()) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Bean class isn't public, and non-public access not allowed: " + beanClass.getName());
}
if (mbd.getFactoryMethodName() != null) {
// 通過工廠方法實例化
return instantiateUsingFactoryMethod(beanName, mbd, args);
}
// Shortcut when re-creating the same bean...
// 是否有構(gòu)造器
if (mbd.resolvedConstructorOrFactoryMethod != null && args == null) {
if (mbd.constructorArgumentsResolved) {
return autowireConstructor(beanName, mbd, null, null);
}
else {
return instantiateBean(beanName, mbd);
}
}
// Need to determine the constructor...
// 需要確認(rèn)構(gòu)造器
Constructor[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
if (ctors != null ||
mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_CONSTRUCTOR ||
mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) {
// 自動裝配铃辖,調(diào)用匹配的構(gòu)造方法進行實例化
return autowireConstructor(beanName, mbd, ctors, args);
}
// No special handling: simply use no-arg constructor.
// 使用默認(rèn)無參構(gòu)造
return instantiateBean(beanName, mbd);
}</pre>
|
這個類用來創(chuàng)建Bean
實例,然后返回BeanWrapper
對象猪叙。注釋寫的很詳細了娇斩。其中有個instantiateBean()
方法,當(dāng)沒有參數(shù)和構(gòu)造方法的時候穴翩,就會調(diào)用該方法來實例化bean犬第。
|
<pre class="prettyprint linenums" style="box-sizing: border-box; background: rgb(231, 229, 220) !important; border: none !important; margin: 0px !important; width: auto !important; float: none !important; clear: none !important; overflow: visible !important; font-family: "Open Sans", "Hiragino Sans GB", "Microsoft YaHei", "WenQuanYi Micro Hei", Arial, Verdana, Tahoma, sans-serif !important; font-size: 14px !important; line-height: 24px !important; padding: 0px 5px !important; white-space: pre !important; box-shadow: rgba(0, 0, 0, 0) 0px 0px 0px !important; border-radius: 0px !important; color: rgb(92, 92, 92) !important; text-align: right !important; min-width: 28px !important;">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
</pre>
|
<pre class="java5 prettyprint linenums" style="box-sizing: border-box; background: transparent !important; border: none !important; margin: 0px !important; width: auto !important; float: none !important; clear: none !important; overflow: visible !important; font-family: monospace; font-size: 14px !important; line-height: 24px !important; padding: 0px 5px !important; white-space: pre !important; box-shadow: rgba(0, 0, 0, 0) 0px 0px 0px !important; border-radius: 0px !important;">// 使用默認(rèn)無參構(gòu)造方法實例化bean
protected BeanWrapper instantiateBean(final String beanName, final RootBeanDefinition mbd) {
try {
Object beanInstance;
final BeanFactory parent = this;
// 獲取JDK安全管理
if (System.getSecurityManager() != null) {
// 根據(jù)實例化策略實例化對象
beanInstance = AccessController.doPrivileged(new PrivilegedAction<Object>() {
public Object run() {
return getInstantiationStrategy().instantiate(mbd, beanName, parent);
}
}, getAccessControlContext());
}
else {
beanInstance = getInstantiationStrategy().instantiate(mbd, beanName, parent);
}
// 對實例化對象進行封裝
BeanWrapper bw = new BeanWrapperImpl(beanInstance);
initBeanWrapper(bw);
return bw;
}
catch (Throwable ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Instantiation of bean failed", ex);
}
}</pre>
|
這個方法是使用默認(rèn)無參構(gòu)造方法實例化bean的,它的核心代碼是getInstantiationStrategy().instantiate(mbd, beanName, parent);
,因為它芒帕,我們可以得到一個bean實例對象歉嗓,然后封裝成BeanWrapper
并返回。
4. SimpleInstantiationStrategy.java
用于BeanFactory的簡單對象實例化策略背蟆。不支持方法注入鉴分,盡管它提供了子類的hook來覆蓋以添加方法注入支持,例如通過重寫方法带膀。
|
<pre class="prettyprint linenums" style="box-sizing: border-box; background: rgb(231, 229, 220) !important; border: none !important; margin: 0px !important; width: auto !important; float: none !important; clear: none !important; overflow: visible !important; font-family: "Open Sans", "Hiragino Sans GB", "Microsoft YaHei", "WenQuanYi Micro Hei", Arial, Verdana, Tahoma, sans-serif !important; font-size: 14px !important; line-height: 24px !important; padding: 0px 5px !important; white-space: pre !important; box-shadow: rgba(0, 0, 0, 0) 0px 0px 0px !important; border-radius: 0px !important; color: rgb(92, 92, 92) !important; text-align: right !important; min-width: 28px !important;">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
</pre>
|
<pre class="java5 prettyprint linenums" style="box-sizing: border-box; background: transparent !important; border: none !important; margin: 0px !important; width: auto !important; float: none !important; clear: none !important; overflow: visible !important; font-family: monospace; font-size: 14px !important; line-height: 24px !important; padding: 0px 5px !important; white-space: pre !important; box-shadow: rgba(0, 0, 0, 0) 0px 0px 0px !important; border-radius: 0px !important;">// 使用初始化策略 實例化bean
public Object instantiate(
RootBeanDefinition beanDefinition, String beanName, BeanFactory owner) {
// Don't override the class with CGLIB if no overrides.
// 如果beanDefinition 中沒有方法覆蓋志珍, 就用jdk,否則用cglib
if (beanDefinition.getMethodOverrides().isEmpty()) {
// 獲取對象的構(gòu)造方法和工廠方法
Constructor constructorToUse = (Constructor) beanDefinition.resolvedConstructorOrFactoryMethod;
if (constructorToUse == null) {
// 如果 沒有構(gòu)造方法和工廠方法垛叨, 使用JDK反射伦糯, 判斷實例化的bean是不是接口
final Class clazz = beanDefinition.getBeanClass();
if (clazz.isInterface()) {
throw new BeanInstantiationException(clazz, "Specified class is an interface");
}
try {
if (System.getSecurityManager() != null) {
// 使用反射獲取bean構(gòu)造方法
constructorToUse = AccessController.doPrivileged(new PrivilegedExceptionAction<Constructor>() {
public Constructor run() throws Exception {
return clazz.getDeclaredConstructor((Class[]) null);
}
});
} else {
constructorToUse = clazz.getDeclaredConstructor((Class[]) null);
}
beanDefinition.resolvedConstructorOrFactoryMethod = constructorToUse;
}
catch (Exception ex) {
throw new BeanInstantiationException(clazz, "No default constructor found", ex);
}
}
// 使用beanUtils實例化 構(gòu)造方法.newInstance(arg) 來實例化
return BeanUtils.instantiateClass(constructorToUse);
}
else {
//如果 有覆蓋或者重寫, 則用CGLIB來實例化對象
// Must generate CGLIB subclass.
return instantiateWithMethodInjection(beanDefinition, beanName, owner);
}
}</pre>
|
總結(jié)它的步驟:
- 如果BeanDefinition的覆蓋方法不為空嗽元,則交給CGLIB來實例化對象敛纲,否則獲取構(gòu)造方法和工廠方法,下一步剂癌。
- 如果沒有構(gòu)造方法和工廠方法淤翔,則使用JDK反射,判斷實例化的bean是不是接口佩谷,如果是办铡,拋出異常,如果不是琳要,則使用反射來獲取bean的構(gòu)造方法寡具,最后,用
構(gòu)造器.newInstance()
的方法(BeanUtils.instantiateClass()
方法底層實現(xiàn))來實例化并返回稚补。
那cglib是如何實例化呢童叠,我們來看下instantiateWithMethodInjection(beanDefinition, beanName, owner);
方法源碼:
|
<pre class="prettyprint linenums" style="box-sizing: border-box; background: rgb(231, 229, 220) !important; border: none !important; margin: 0px !important; width: auto !important; float: none !important; clear: none !important; overflow: visible !important; font-family: "Open Sans", "Hiragino Sans GB", "Microsoft YaHei", "WenQuanYi Micro Hei", Arial, Verdana, Tahoma, sans-serif !important; font-size: 14px !important; line-height: 24px !important; padding: 0px 5px !important; white-space: pre !important; box-shadow: rgba(0, 0, 0, 0) 0px 0px 0px !important; border-radius: 0px !important; color: rgb(92, 92, 92) !important; text-align: right !important; min-width: 28px !important;">1
2
3
4
5
6
7
</pre>
|
<pre class="java5 prettyprint linenums" style="box-sizing: border-box; background: transparent !important; border: none !important; margin: 0px !important; width: auto !important; float: none !important; clear: none !important; overflow: visible !important; font-family: monospace; font-size: 14px !important; line-height: 24px !important; padding: 0px 5px !important; white-space: pre !important; box-shadow: rgba(0, 0, 0, 0) 0px 0px 0px !important; border-radius: 0px !important;">@Override
protected Object instantiateWithMethodInjection(
RootBeanDefinition beanDefinition, String beanName, BeanFactory owner) {
// Must generate CGLIB subclass.
return new CglibSubclassCreator(beanDefinition, owner).instantiate(null, null);
}</pre>
|
然后再跟進CglibSubclassCreator(beanDefinition, owner).instantiate(null, null);
方法:
|
<pre class="prettyprint linenums" style="box-sizing: border-box; background: rgb(231, 229, 220) !important; border: none !important; margin: 0px !important; width: auto !important; float: none !important; clear: none !important; overflow: visible !important; font-family: "Open Sans", "Hiragino Sans GB", "Microsoft YaHei", "WenQuanYi Micro Hei", Arial, Verdana, Tahoma, sans-serif !important; font-size: 14px !important; line-height: 24px !important; padding: 0px 5px !important; white-space: pre !important; box-shadow: rgba(0, 0, 0, 0) 0px 0px 0px !important; border-radius: 0px !important; color: rgb(92, 92, 92) !important; text-align: right !important; min-width: 28px !important;">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
</pre>
|
<pre class="java5 prettyprint linenums" style="box-sizing: border-box; background: transparent !important; border: none !important; margin: 0px !important; width: auto !important; float: none !important; clear: none !important; overflow: visible !important; font-family: monospace; font-size: 14px !important; line-height: 24px !important; padding: 0px 5px !important; white-space: pre !important; box-shadow: rgba(0, 0, 0, 0) 0px 0px 0px !important; border-radius: 0px !important;">// 使用cglib 來進行bean實例化
public Object instantiate(Constructor ctor, Object[] args) {
// cglib
Enhancer enhancer = new Enhancer();
// bean本身作為基類
enhancer.setSuperclass(this.beanDefinition.getBeanClass());
enhancer.setCallbackFilter(new CallbackFilterImpl());
enhancer.setCallbacks(new Callback[] {
NoOp.INSTANCE,
new LookupOverrideMethodInterceptor(),
new ReplaceOverrideMethodInterceptor()
});
// 生成實例對象
return (ctor == null) ?
enhancer.create() :
enhancer.create(ctor.getParameterTypes(), args);
}</pre>
|
從上面代碼可以看到,這就是CGLIB動態(tài)代理中創(chuàng)建代理的過程代碼,不熟悉的可以往前翻徹底搞懂動態(tài)代理
章節(jié)的內(nèi)容厦坛。
好了五垮,到了這里,Spring就完成了bean實例的創(chuàng)建杜秸,但是此時就能拿著這個實例去使用嗎放仗,顯然是不可以,因為屬性還沒有被賦入撬碟,下一章再繼續(xù)介紹如何將屬性依賴關(guān)系注入到Bean實例對象诞挨。