手写简版spring --2--实现Bean的定义、注册、获取
一、目標(biāo)
在上一章節(jié)我們初步依照 Spring Bean 容器的概念,實(shí)現(xiàn)了一個(gè)粗糙版本的代碼實(shí)現(xiàn)。那么本章節(jié)我們需要結(jié)合已實(shí)現(xiàn)的 Spring Bean 容器進(jìn)行功能完善,實(shí)現(xiàn) Bean 容器關(guān)于 Bean 對象的注冊和獲取。這一次我們把 Bean 的創(chuàng)建交給容器,而不是我們在調(diào)用時(shí)候傳遞一個(gè)實(shí)例化好的 Bean 對象,另外還需要考慮單例對象,在對象的二次獲取時(shí)是可以從內(nèi)存中獲取對象的。此外不僅要實(shí)現(xiàn)功能還需要完善基礎(chǔ)容器框架的類結(jié)構(gòu)體,否則將來就很難擴(kuò)容進(jìn)去其他的功能了。
二、設(shè)計(jì)
鑒于本章節(jié)的案例目標(biāo),我們需要將 Spring Bean 容器完善起來,首先非常重要的一點(diǎn)是在 Bean 注冊的時(shí)候只注冊一個(gè)類信息,而不會直接把實(shí)例化信息注冊到 Spring 容器中。那么就需要修改 BeanDefinition 中的屬性 Object 為 Class,接下來在需要做的就是在獲取 Bean 對象時(shí)需要處理 Bean 對象的實(shí)例化操作以及判斷當(dāng)前單例對象在容器中是否已經(jīng)緩存起來了。整體設(shè)計(jì)如下
以下內(nèi)容其實(shí)就是圍繞著Spring的容器需要有單例,緩存,實(shí)例化,異常這些功能展開的
- 首先我們需要定義 BeanFactory 這樣一個(gè) Bean 工廠,提供 Bean 的獲取方法getBean(String name),之后這個(gè) Bean 工廠接口由抽象類AbstractBeanFactory 實(shí)現(xiàn)。這樣使用模板模式的設(shè)計(jì)方式,可以統(tǒng)一收口通用核心方法的調(diào)用邏輯和標(biāo)準(zhǔn)定義,也就很好的控制了后續(xù)的實(shí)現(xiàn)者不用關(guān)心調(diào)用邏輯,按照統(tǒng)一方式執(zhí)行。那么類的繼承者只需要關(guān)心具體方法的邏輯實(shí)現(xiàn)即可。
- 那么在繼承抽象類 AbstractBeanFactory 后的AbstractAutowireCapableBeanFactory 就可以實(shí)現(xiàn)相應(yīng)的抽象方法了,因?yàn)锳bstractAutowireCapableBeanFactory 本身也是一個(gè)抽象類,所以它只會實(shí)現(xiàn)屬于自己的抽象方法,其他抽象方法由繼承 AbstractAutowireCapableBeanFactory 的類實(shí)現(xiàn)。這里就體現(xiàn)了類實(shí)現(xiàn)過程中的各司其職,你只需要關(guān)心屬于你的內(nèi)容,不是你的內(nèi)容,不要參與。這一部分內(nèi)容我們會在代碼里有具體的體現(xiàn)
- 另外這里還有塊非常重要的知識點(diǎn),就是關(guān)于單例 SingletonBeanRegistry 的接口定義實(shí)現(xiàn),而 DefaultSingletonBeanRegistry 對接口實(shí)現(xiàn)后,會被抽象類AbstractBeanFactory 繼承。現(xiàn)在 AbstractBeanFactory 就是一個(gè)非常完整且強(qiáng)大的抽象類了,也能非常好的體現(xiàn)出它對模板模式的抽象定義。接下來我們就帶著這些設(shè)計(jì)層面的思考,去看代碼的具體實(shí)現(xiàn)結(jié)果
- 類依賴圖
基本都是接口做出約定,抽象類給出場景,子類具體實(shí)現(xiàn),然后接口調(diào)用。
這一章節(jié)關(guān)于 Spring Bean 容器的功能實(shí)現(xiàn)與 Spring 源碼中還有不少的差距,但以目前實(shí)現(xiàn)結(jié)果的類關(guān)系圖來看,其實(shí)已經(jīng)具備了一定的設(shè)計(jì)復(fù)雜性,這些復(fù)雜的類關(guān)系設(shè)計(jì)在各個(gè)接口定義和實(shí)現(xiàn)以及在抽象類繼承中都有所體現(xiàn),例如:
- BeanFactory 的定義由 AbstractBeanFactory 抽象類實(shí)現(xiàn)接口的 getBean 方法
- 而AbstractBeanFactory 又繼承了實(shí)現(xiàn)了 SingletonBeanRegistry 的DefaultSingletonBeanRegistry 類。這樣 AbstractBeanFactory 抽象類就具備了單例 Bean的注冊功能。
- AbstractBeanFactory 中又定義了兩個(gè)抽象方法: getBeanDefinition(StringbeanName) 、 createBean(String beanName, BeanDefinition beanDefinition) ,而這兩個(gè)抽象方法分別由DefaultListableBeanFactory 、AbstractAutowireCapableBeanFactory 實(shí)現(xiàn)。
- 最終 DefaultListableBeanFactory 還會繼承抽象類AbstractAutowireCapableBeanFactory 也就可以調(diào)用抽象類中的 createBean 方法了。
通過最終的DefaultListableBeanfatory new出的對象beanFactory已經(jīng)具備了很多功能。
怎么設(shè)計(jì)還是體現(xiàn)一個(gè)最基本的原則:類實(shí)現(xiàn)過程中的各司其職,你只需要關(guān)心屬于你的內(nèi)容,不是你的內(nèi)容,不要參與。
三、代碼實(shí)現(xiàn)
- 工程結(jié)構(gòu)
- BeanDefinition
- SingletonBeanRegistry
- SingletonBeanRegistry
- 抽象類定義模板方法 (AbstarctBeanFactory)
- AbstractBeanFactory 首先繼承了 DefaultSingletonBeanRegistry ,也就具備了使用單例注冊類方法。
- 接下來很重要的一點(diǎn)是關(guān)于接口 BeanFactory 的實(shí)現(xiàn),在方法 getBean 的實(shí)現(xiàn)過程中可以看到,主要是對單例 Bean 對象的獲取以及在獲取不到時(shí)需要拿到 Bean的定義做相應(yīng) Bean 實(shí)例化操作。那么 getBean 并沒有自身的去實(shí)現(xiàn)這些方法,而是只定義了調(diào)用過程以及提供了抽象方法,由實(shí)現(xiàn)此抽象類的其他類做相應(yīng)實(shí)現(xiàn)。
- 后續(xù)繼承抽象類 Abstrac tBeanFactory 的類有兩個(gè),包括:AbstractAutowireCapableBeanFactory 、 DefaultListableBeanFactory ,這兩個(gè)類分別做了相應(yīng)的實(shí)現(xiàn)處理,接著往下看。
- AbstractAutowireCapableBeanFactory
- 在 AbstractAutowireCapableBeanFactory 類中實(shí)現(xiàn)了 Bean 的實(shí)例化操作newInstance ,其實(shí)這塊會埋下一個(gè)坑,有構(gòu)造函數(shù)入?yún)⒌膶ο笤趺刺幚??
- 在處理完 Bean 對象的實(shí)例化后,直接調(diào)用 addSingleton 方法存放到單例對象的緩存中去。
- 核心類實(shí)現(xiàn) (DefaultListableBeanFactory)
- DefaultListableBeanFactory 在 Spring 源碼中也是一個(gè)非常核心的類,在我們目前的實(shí)現(xiàn)中也是逐步貼近于源碼,與源碼類名保持一致。
- DefaultListableBeanFactory 繼承了 AbstractAutowireCapableBeanFactory 類,也就具備了接口 BeanFactory 和 AbstractBeanFactory 等一連串的功能實(shí)現(xiàn)。 所以有時(shí)候你會看到一些類的強(qiáng)轉(zhuǎn),調(diào)用某些方法,也是因?yàn)槟銖?qiáng)轉(zhuǎn)的類實(shí)現(xiàn)接口或繼承了某些類。
- 除此之外這個(gè)類還實(shí)現(xiàn)了接口 BeanDefinitionRegistry 中的registerBeanDefinition(String beanName, BeanDefinition beanDefinition) 方法,當(dāng)然你還會看到一個(gè) getBeanDefinition 的實(shí)現(xiàn),這個(gè)方法我們文中提到過它是抽象類 AbstractBeanFactory 中定義的抽象方法。 現(xiàn)在注冊 Bean 定義與獲取 Bean 定義。就可以同時(shí)使用了,是不感覺這個(gè)套路還蠻深的。接口定義了注冊,抽象類定義了獲取,都集中在 DefaultListableBeanFactory 中的 beanDefinitionMap 里
四、測試
- 事先準(zhǔn)備
- 測試
- 在此次的單元測試中除了包括;Bean 工廠、注冊 Bean、獲取 Bean,三個(gè)步驟,還額外增加了一次對象的獲取和調(diào)用。這里主要測試驗(yàn)證單例對象的是否正確的存放到了緩存中。
- 此外與上一章節(jié)測試過程中不同的是,我們把 UserService.class 傳遞給了 BeanDefinition 而不是像上一章節(jié)那樣直接 new UserService() 操作。]
五、總結(jié)
總結(jié)
以上是生活随笔為你收集整理的手写简版spring --2--实现Bean的定义、注册、获取的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 回首阿里10年产品经理路,1点忠告希望在
- 下一篇: 利用这些心理学效应,轻松拿到满意offe