官术网_书友最值得收藏!

2.2.2 Bean的實例化

請注意,到現在為止,Spring IoC容器對Bean的創建過程并沒有完成,我們只是將Bean的定義加載到了容器中而已。但是容器本身可能已經存在這些Bean的定義,所以我們還需要調用ApplicationContext接口的抽象實現類AbstractApplicationContext中的refresh()方法刷新容器,正如我們在前面看到的AnnotationConfigApplicationContext構造函數所執行的那樣。可以說,refresh()方法是整個Spring容器中最為核心的一個方法,值得我們詳細討論。但因為這里關注的是依賴注入,所以我們只列出refresh()方法中與該主題相關的代碼,如代碼清單2-13所示。

代碼清單2-13 AbstractApplicationContext中的refresh()方法代碼

@Override
public void refresh() throws BeansException, IllegalStateException {
    synchronized (this.startupShutdownMonitor) {
        // 提取配置信息轉化為BeanDefinition并注冊到BeanFactory中
        ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

        try {
            ...
            // 初始化所有的單例Bean
            finishBeanFactoryInitialization(beanFactory);
            ...
        }
    }
}

可以看到,obtainFreshBeanFactory()方法完成BeanDefinition的注冊并返回一個Bean-Factory。對于AnnotationConfigApplicationContext而言,這一步實際上就是將BeanDefinition注冊到DefaultListableBeanFactory而已,我們在前面已經介紹了這一步驟。

而finishBeanFactoryInitialization()方法才是真正的完成Bean實例化的入口。在這個方法中,完成Bean的實例化代碼實際上位于它的子類DefaultListableBeanFactory中,如代碼清單2-14所示。

代碼清單2-14 DefaultListableBeanFactory中的preInstantiateSingletons()方法代碼

@Override
public void preInstantiateSingletons() throws BeansException {
    List<String> beanNames = new ArrayList<String>(this.beanDefinitionNames);

    // 觸發所有非懶加載的單例Bean的初始化操作
    for (String beanName : beanNames) {
        ...
        //獲取Bean
        getBean(beanName);
        ...
    }
}

接下來,我們就進入到getBean()方法了,這個方法可以從BeanFactory中獲取一個Bean,而Bean的初始化過程也被封裝在這個方法中。在getBean()方法中,我們一路跟蹤代碼會發現需要深入分析的實際上是如代碼清單2-15所示的一個createBean()抽象方法。

代碼清單2-15 BeanFactory中的createBean()方法代碼

protected abstract Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) throws BeanCreationException;

請注意,在Spring中,實現這個抽象方法的唯一BeanFactory是AbstractAutowireCap-ableBeanFactory。從命名上看,我們就可以聯想到@Autowired注解。在AbstractAutowire-CapableBeanFactory中,真正完成Bean的創建是在doCreateBean()方法中。doCreateBean()方法比較長,為了顯示得更簡潔,我們對代碼做了大量裁剪之后得到如代碼清單2-16所示的結構。

代碼清單2-16 AbstractAutowireCapableBeanFactory中的doCreateBean()方法代碼結構

protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args) throws BeanCreationException {
    //1. 初始化Bean
    instanceWrapper = createBeanInstance(beanName, mbd, args);

    //2. 初始化Bean實例
    populateBean(beanName, mbd, instanceWrapper);

    //3. 執行初始化Bean實例的回調
    exposedObject = initializeBean(beanName, exposedObject, mbd);

    return exposedObject;
}

可以看到這里包含三個核心子方法,它們的名稱和作用如圖2-2所示。

045-1

圖2-2 單例對象的初始化步驟示意圖

在以上三個步驟中,createBeanInstance()方法用于根據配置生成具體的Bean,最終通過基于構造器的反射方法實現這一目標。請注意,執行完這一步之后,Bean已經被創建了,但還不完整,因為屬性還沒有被注入。

接下來的populateBean()方法就是用于實現屬性的自動注入,包含byName、byType類型的自動裝配,以及基于@Autowired、@Value注解的屬性設值。執行完這一步之后,可以說Bean已經是完整的了。

而最后的initializeBean()方法則更多是一種擴展性的實現機制,用于在Bean初始化完成之后執行一些定制化操作。

至此,針對整個Bean的注入過程(即Bean的注冊和實例化),我們圍繞核心流程做了剖析和總結。在這個過程中,比較容易碰到的一個問題就是陷入代碼的細節而忽略了主體步驟。因此,如果想要跳出源碼閱讀的困境,快速掌握框架的實現原理,我們就必須從核心流程來看待框架。

接下來,我們將對Spring依賴注入中典型的循環依賴問題進行系統分析。可以說,想要理解循環依賴問題以及對應的解決方案,掌握本節闡述的Bean的注冊和實例化原理至關重要。

主站蜘蛛池模板: 益阳市| 钟山县| 孟州市| 双鸭山市| 中阳县| 和平县| 穆棱市| 孟州市| 乌兰察布市| 临沧市| 闵行区| 台安县| 阜平县| 菏泽市| 丰城市| 肇东市| 上饶市| 南康市| 东山县| 额尔古纳市| 舞钢市| 蕉岭县| 凌云县| 怀仁县| 南木林县| 信阳市| 安福县| 沂源县| 都匀市| 璧山县| 武邑县| 克什克腾旗| 林西县| 黑山县| 阆中市| 桑日县| 凌海市| 澜沧| 峨山| 枞阳县| 巴东县|