Spring IoC源碼分析(注解版) -- 上

最近有時(shí)間讀了一下Spring的源碼,順便記錄一下筆記,加深理解。關(guān)于Spring IoC源碼分析,網(wǎng)上有一篇文章寫(xiě)得很詳細(xì),叫Spring IOC 容器源碼分析,大家可以去看看。這篇文章是基于XML的,因?yàn)楣ぷ髦谢谧⒔獾姆绞接玫枚嘁恍?,所以就讀了一下Spring IoC注解版本的源代碼。為了更方便的分析源碼,有時(shí)候需要對(duì)代碼一步一步進(jìn)行調(diào)試,所以我寫(xiě)了一個(gè)簡(jiǎn)單的spring-ioc-analysis,放在github上,供大家參考。

整個(gè)分析過(guò)程大概分為4篇(上,中,下和總結(jié)篇),因?yàn)闀r(shí)間和水平有限,筆記中如果有錯(cuò)誤之處,歡迎大家指正。

核心概念

在分析Spring IoC源碼之前,需要弄清楚一些核心概念。

BeanDefinition

這個(gè)是一個(gè)接口,它是用來(lái)存儲(chǔ)Bean定義的一些信息的,比如ClassName,Scope,init-methon,等等。它的實(shí)現(xiàn)有RootBeanDefination,AnnotatedGenericBeanDefinition等。

BeanDefinitionHolder

這是BeanDefination的包裝類(lèi),用來(lái)存儲(chǔ)BeanDefinition,name以及aliases等。

BeanFactory & AbstractBeanFactory

BeanFactory就是Bean工廠啦,所有的Bean都由BeanFactory統(tǒng)一創(chuàng)建和管理,Spring提供了一個(gè)AbstractBeanFactory,它繼承了BeanFactory接口,并且實(shí)現(xiàn)了大部分BeanFactory的功能。

AbstractBeanFactory有一個(gè)非常重要的方法叫g(shù)etBean()

public <T> T getBean(String name, Class<T> requiredType) throws BeansException {
        return doGetBean(name, requiredType, null, false);
    }

它是用來(lái)根據(jù)名字和類(lèi)型獲取Bean對(duì)象的。它獲取對(duì)象的原理是,如果BeanFactory中存在Bean,則從緩存中取Bean,否則創(chuàng)建并返回該Bean,并且將該Bean添加到緩存中(這里指Singleton類(lèi)型的Bean)。所以確切的講,Bean是在什么時(shí)候創(chuàng)建的,要看什么時(shí)候調(diào)用getBean方法獲取這個(gè)Bean,根據(jù)Bean定義的不同,getBean方法會(huì)在不同時(shí)候被調(diào)用。Spring中Bean大致可以分為兩類(lèi),應(yīng)用類(lèi)Bean(被應(yīng)用程序使用)以及功能性Bean(被Spring使用)。Spring提供了一些功能性接口如BeanFactoryPostProcessor和BeanPostProcessor,實(shí)現(xiàn)了這些接口的Bean可以成為功能性Bean。如果Bean實(shí)現(xiàn)了BeanFactoryPostProcessor,則在refresh方法中調(diào)用invokeBeanFactoryPostProcessors方法時(shí)創(chuàng)建Bean,如果實(shí)現(xiàn)了BeanPostProcessor方法,則在registerBeanPostProcessors方法中創(chuàng)建Bean。其它的Bean應(yīng)該屬于應(yīng)用類(lèi)Bean,在默認(rèn)的finishBeanFactoryInitialization方法中創(chuàng)建Bean,這在后邊還會(huì)講到。

AnnotationConfigApplicationContext & BeanFactory & BeanDefinitionRegistry & DefaultListableBeanFactory

這幾個(gè)類(lèi)的關(guān)系也是很重要的,我們來(lái)捋一捋。

AnnotationConfigApplicationContext這個(gè)類(lèi)是基于注解的容器類(lèi),它實(shí)現(xiàn)了BeanFactory和BeanDefinitionRegistry兩個(gè)接口,擁有Bean對(duì)象的管理和BeanDefinition注冊(cè)功能。同時(shí)這個(gè)類(lèi)擁有一個(gè)DefaultListableBeanFactory的對(duì)象。

DefaultListableBeanFactory也實(shí)現(xiàn)了BeanFactory和BeanDefinitionRegistry接口,擁有Bean對(duì)象管理和BeanDefinition注冊(cè)功能。AnnotationConfigApplicationContext是委托DefaultListableBeanFactory來(lái)實(shí)現(xiàn)對(duì)象管理和BeanDefinition注冊(cè)的。這里使用的是代理模式。

介紹完了核心概念,我們來(lái)開(kāi)始分析源碼,剖析Spring 容器的加載過(guò)程。Spring容器啟動(dòng)過(guò)程主要做了兩件事情:

  • 加載BeanDefinition
  • 創(chuàng)建Bean

我們先來(lái)看BeanDefinition的加載過(guò)程。

加載BeanDefinition

我們創(chuàng)建一個(gè)簡(jiǎn)單Maven工程,在main函數(shù)中輸入如下代碼,就啟動(dòng)了一個(gè)基于注解的Spring容器,并從容器中獲取helloService對(duì)象。

public static void main(String[] args) {
        AbstractApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);
        context.registerShutdownHook();
        HelloService helloService = context.getBean(HelloService.class);
        helloService.sayHello();
    }

之所以要使用AbstractApplicationContext類(lèi),是因?yàn)槲覀兊腍elloService實(shí)現(xiàn)了一些BeanPostProcessor這樣的接口,需要調(diào)用AnnotationConfigApplicationContext對(duì)象的registerShutdownHook方法。

現(xiàn)在來(lái)分析源碼,進(jìn)入AnnotationConfigApplicationContext的構(gòu)造函數(shù):

public AnnotationConfigApplicationContext(Class<?>... annotatedClasses) {
        this();
        register(annotatedClasses);
        refresh();
    }

兩個(gè)主方法,resister和refresh。

register

進(jìn)入register方法,它調(diào)用了reader.register方法。

public void register(Class<?>... annotatedClasses) {
        Assert.notEmpty(annotatedClasses, "At least one annotated class must be specified");
        this.reader.register(annotatedClasses);
    }

這個(gè)reader是AnnotatedBeanDefinitionReader類(lèi)的一個(gè)實(shí)例,在AnnotationConfigApplicationContext的構(gòu)造函數(shù)中創(chuàng)建的。構(gòu)造函數(shù)還創(chuàng)建了一個(gè)scanner,用于包掃描。

public AnnotationConfigApplicationContext() {
        this.reader = new AnnotatedBeanDefinitionReader(this);
        this.scanner = new ClassPathBeanDefinitionScanner(this);
    }

進(jìn)入reader的register方法:


    public void register(Class<?>... annotatedClasses) {
        for (Class<?> annotatedClass : annotatedClasses) {
            registerBean(annotatedClass);
        }
    }

    public void registerBean(Class<?> annotatedClass) {
        doRegisterBean(annotatedClass, null, null, null);
    }


    <T> void doRegisterBean(Class<T> annotatedClass, @Nullable Supplier<T> instanceSupplier, @Nullable String name,
            @Nullable Class<? extends Annotation>[] qualifiers, BeanDefinitionCustomizer... definitionCustomizers) {

        // 創(chuàng)建BeanDefinition
        AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(annotatedClass);
        // 生成bean name
        String beanName = (name != null ? name : this.beanNameGenerator.generateBeanName(abd, this.registry));

        AnnotationConfigUtils.processCommonDefinitionAnnotations(abd);
        
        // ...省去了其它代碼

        // 創(chuàng)建BeanDefinitionHolder,它是BeanDefiniton的一個(gè)包裝類(lèi),包含BeanDefiniton對(duì)象和它的名字
        BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd, beanName);
        // 最后調(diào)用registerBeanDefinition
        BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);
    }

限于篇幅,我們只分析一些比較重要的源代碼,其它的源代碼都被我刪除了。進(jìn)入BeanDefinitionReaderUtils.registerBeanDefinition

public static void registerBeanDefinition(
            BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
            throws BeanDefinitionStoreException {

        // Register bean definition under primary name.
        String beanName = definitionHolder.getBeanName();
        // 調(diào)用registry的registerBeanDefinition方法,registry是我們傳進(jìn)來(lái)的AnnotationConfigApplicationContext,因?yàn)樗鼘?shí)現(xiàn)了BeanDefinitionRegistry,所以我們進(jìn)入AnnotationConfigApplicationContext的registerBeanDefinition方法。
        registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());

        // Register aliases for bean name, if any.
        String[] aliases = definitionHolder.getAliases();
        if (aliases != null) {
            for (String alias : aliases) {
                registry.registerAlias(beanName, alias);
            }
        }
    }

進(jìn)入AnnotationConfigApplicationContext的registerBeanDefinition方法。好奇怪,怎么沒(méi)有呢,原來(lái)在它的父類(lèi)GenericApplicationContext中。來(lái)看代碼:

public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
            throws BeanDefinitionStoreException {

        // 調(diào)用beanFactory的registerBeanDefinition。我們之前講過(guò),AnnotationConfigApplicationContext是委托DefaultListableBeanFactory來(lái)注冊(cè)BeanDefinition和管理Bean的,所以調(diào)用了beanFactory的registerBeanDefinition
        this.beanFactory.registerBeanDefinition(beanName, beanDefinition);
    }

在GenericApplicationContext的構(gòu)造函數(shù)中,創(chuàng)建了這個(gè)beanFactory。

public GenericApplicationContext() {
        // 前面也講過(guò),DefaultListableBeanFactory也實(shí)現(xiàn)了BeanDefinitionRegistry和BeanFactory接口的。
        this.beanFactory = new DefaultListableBeanFactory();
    }

既然beanFactory是DefaultListableBeanFactory的實(shí)例,所以進(jìn)入DefaultListableBeanFactory的registerBeanDefinition方法咯。

public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
            throws BeanDefinitionStoreException {
    
        
        //... 省去重復(fù)注冊(cè)代碼邏輯以及其它一些邏輯判斷,
    
        //最終執(zhí)行以下代碼,可以看出,最終是將beanDefinition放到beanDefinitionMap中。所有的beanDefinition都會(huì)放到這個(gè)map中,以beanName為主鍵。如果一個(gè)beanDefinition有多個(gè)別名,那個(gè)它會(huì)被注冊(cè)多次。
        this.beanDefinitionMap.put(beanName, beanDefinition);
    }

好啦,到這里為止,register方法就分析完成了。但是bean定義全部注冊(cè)完了嗎,還沒(méi)有。這里只是注冊(cè)完了配置文件的bean definition。至于我們自己注入的類(lèi),或者通過(guò)掃描注入的類(lèi),在refresh方法中,我們會(huì)在下一篇分析。

總結(jié)

我們今天講了Spring IoC容器源碼分析的第一部分,主要講了一些核心概念,以及BeanDefinition的加載過(guò)程。

在Spring中,所有用戶定義的Bean都會(huì)以BeanDefinition的方式注冊(cè)到BeanFactory中。BeanDefinition相當(dāng)于Bean的元數(shù)據(jù),描述了Bean定義的一些屬性。

我們講了AnnotationConfigApplicationContext,BeanFactory,BeanDefinitionRegistry, DefaultListableBeanFactory。AnnotationConfigApplicationContext實(shí)現(xiàn)了BeanFactory和BeanDefinitionRegistry接口,DefaultListableBeanFactory也實(shí)現(xiàn)了DefaultListableBeanFactory接口。而AnnotationConfigApplicationContext中BeanDefinition的注冊(cè)和Bean的管理,是委托給DefaultListableBeanFactory去完成的。

另外我們也分析了BeanDefinition的register過(guò)程,也確認(rèn)了AnnotationConfigApplicationContext注冊(cè)BeanDefinition確實(shí)是委托給DefaultListableBeanFactory來(lái)完成的。最終BeanDefinition被存儲(chǔ)在一個(gè)Map中,以beanName為key,以BeanDefinition對(duì)象為值。

我們下一篇會(huì)繼續(xù)講refresh方法。


所有文章在Github上同步,你也可以訪問(wèn)我的個(gè)人博客點(diǎn)擊查看

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容