那什么是依賴注入呢 Day53 2019-01-12

終于拿到offer了窑睁,但是還是想試試下周幾家大公司挺峡,努力準(zhǔn)備吧,不可懈档Eァ橱赠!
那什么是依賴注入呢?

所謂依賴注入,就是由IOC容器在運行期間箫津,動態(tài)地將某種依賴關(guān)系注入到對象之中病线。再完成IOC容器初始化之后,也就是所謂的Bean加載完成后鲤嫡,我們需要對這些Bean進行調(diào)用和獲取送挑,這個過程就叫依賴注入。

那什么時候會觸發(fā)依賴注入呢?

  1. 通過getBean()方法獲取Bean對象暖眼。
  2. 給Bean配置了懶加載惕耕,ApplicationContext啟動完成后調(diào)用getBean()來實例化對象。

現(xiàn)在計算機性能已經(jīng)足夠诫肠,不是特殊要求下盡量別做懶加載司澎,這樣的話可以減少web運行時的調(diào)用時間開銷。

好了栋豫,介紹完這些就開始我們的DI之旅挤安。

1. BeanFactory

通過Spring獲取Bean的最根本的接口。

image

|

<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é)以下它都做了什么事情:

  1. 根據(jù)傳來的beanname(有可能是別名)來獲取真正的bean名稱:beanName泣刹。

  2. 根據(jù)beanName獲取單例實例,如果有直接獲取到bean實例并返回犀被,DI完成椅您。

  3. 如果根據(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ù)該單例對象和beanNameargs創(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é)以下它都做了什么:

  1. 確定beanNameRootBeanDefinition可以被實例化。
  2. 執(zhí)行方法覆蓋
  3. BeanPostProcessors能否再解析之前獲取到bean瞎颗,如果能則直接返回件甥,否則下一步捌议。
  4. 調(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é)以下它干的事情:

  1. 根據(jù)beanName獲取beanWrapper對象虐秦。如果beanWrapper對象是空平酿,則調(diào)用createBeanInstance()方法創(chuàng)建bean實例。否則悦陋,下一步
  2. 通過beanWrapper對象獲取bean實例和class類型蜈彼。
  3. 允許 postProcessors 調(diào)整組合BeanDefinition
  4. 如果RootBeanDefinition是單例并且允許循環(huán)引用并且beanName正在進行單例創(chuàng)建俺驶,將beanName添加到單例工廠幸逆。
  5. 調(diào)用populateBean()方法給bean的屬性值賦值,然后初始化bean對象并返回創(chuàng)建的bean實例暮现,如果拋異常还绘,則下一步。
  6. 如果該beanName對象已經(jīng)注冊單例模式栖袋,則從單例中獲取拍顷,并判斷獲取到的bean實例(B)與BeanWrapper中的bean實例(A)是同一個實例,如果是塘幅,則返回A或者B昔案,如果不是,則遞歸找出它的依賴bean电媳。
  7. 返回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é)它的步驟:

  1. 如果BeanDefinition的覆蓋方法不為空嗽元,則交給CGLIB來實例化對象敛纲,否則獲取構(gòu)造方法和工廠方法,下一步剂癌。
  2. 如果沒有構(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實例對象诞挨。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市呢蛤,隨后出現(xiàn)的幾起案子惶傻,更是在濱河造成了極大的恐慌,老刑警劉巖其障,帶你破解...
    沈念sama閱讀 216,544評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件银室,死亡現(xiàn)場離奇詭異,居然都是意外死亡励翼,警方通過查閱死者的電腦和手機蜈敢,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,430評論 3 392
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來汽抚,“玉大人扶认,你說我怎么就攤上這事∈獬龋” “怎么了辐宾?”我有些...
    開封第一講書人閱讀 162,764評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長膨蛮。 經(jīng)常有香客問我叠纹,道長,這世上最難降的妖魔是什么敞葛? 我笑而不...
    開封第一講書人閱讀 58,193評論 1 292
  • 正文 為了忘掉前任誉察,我火速辦了婚禮,結(jié)果婚禮上惹谐,老公的妹妹穿的比我還像新娘持偏。我一直安慰自己,他們只是感情好氨肌,可當(dāng)我...
    茶點故事閱讀 67,216評論 6 388
  • 文/花漫 我一把揭開白布鸿秆。 她就那樣靜靜地躺著,像睡著了一般怎囚。 火紅的嫁衣襯著肌膚如雪卿叽。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,182評論 1 299
  • 那天,我揣著相機與錄音考婴,去河邊找鬼贩虾。 笑死,一個胖子當(dāng)著我的面吹牛沥阱,可吹牛的內(nèi)容都是我干的缎罢。 我是一名探鬼主播,決...
    沈念sama閱讀 40,063評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼考杉,長吁一口氣:“原來是場噩夢啊……” “哼策精!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起奔则,我...
    開封第一講書人閱讀 38,917評論 0 274
  • 序言:老撾萬榮一對情侶失蹤蛮寂,失蹤者是張志新(化名)和其女友劉穎蔽午,沒想到半個月后易茬,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,329評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡及老,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,543評論 2 332
  • 正文 我和宋清朗相戀三年抽莱,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片骄恶。...
    茶點故事閱讀 39,722評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡食铐,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出僧鲁,到底是詐尸還是另有隱情虐呻,我是刑警寧澤,帶...
    沈念sama閱讀 35,425評論 5 343
  • 正文 年R本政府宣布寞秃,位于F島的核電站斟叼,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏春寿。R本人自食惡果不足惜朗涩,卻給世界環(huán)境...
    茶點故事閱讀 41,019評論 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望绑改。 院中可真熱鬧谢床,春花似錦、人聲如沸厘线。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,671評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽造壮。三九已至覆履,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背硝全。 一陣腳步聲響...
    開封第一講書人閱讀 32,825評論 1 269
  • 我被黑心中介騙來泰國打工栖雾, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人伟众。 一個月前我還...
    沈念sama閱讀 47,729評論 2 368
  • 正文 我出身青樓析藕,卻偏偏與公主長得像,于是被迫代替她去往敵國和親凳厢。 傳聞我的和親對象是個殘疾皇子账胧,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,614評論 2 353

推薦閱讀更多精彩內(nèi)容