Dubbo-SPI和IoC的前世此生

前言

在上一篇的末尾,咱們提到了dubbospi中增長了IoCAOP的功能.那麼本篇就講一下這個增長的IoC,spi部分預計會有四篇,由於這東西實在是過重要了.溫故而知新,咱們先來回顧一下,咱們以前都講了什麼.java

提到IoC,你們第一個想到的就是Spring,因此Spring的IoC也是本篇的一大重點內容.固然畢竟主題是dubbo,因此對於Spring內容,將與dubbo結合,以短小精幹,可是又不缺少深度的介紹.(後期若是你們有須要,也能夠開展Spring源碼專題)學習

看到這裏可能有同窗就會問,肥朝你不是寫dubbo源碼解析的嗎,爲何還要講Spring呢?dubbo中涉及到不少的邊緣知識,其中包括SpringNettyZookeeper等等,我但願的是,你們能經過學習dubbo爲主線,全面綜合的提升本身,而不是爲了看源碼而看源碼,也不是爲了面試而看源碼.url

插播面試題

  • 你提到了dubbo中spi也增長了IoC,那你先講講Spring的IoC,而後再講講dubbo裏面又是怎麼作的

Spring的IoC

容器

Spirng的IoC容器主要有兩種,即BeanFactoryApplicationContextspa

  • BeanFactory是Spring中最底層的接口,只提供了最簡單的IoC功能,負責配置,建立和管理bean.
  • ApplicationContext繼承了BeanFactory,擁有了基本的IoC功能外,還支持
    • 國際化
    • 消息機制
    • 統一的資源加載
    • AOP

另外ApplicationContext在加載的時候就會建立全部的bean(Web應用推薦),BeanFactory須要等到拿bean的時候纔會建立bean(桌面應用推薦).因此,咱們通常使用ApplicationContext設計

整體流程

實現IoC的過程,整體能夠分爲兩步,以下圖3d

容器啓動階段

該階段至關於"根據圖紙裝配成生產線",也就是對象管理信息的收集.code

Bean實例化階段

該階段至關於"根據生產線來生產具體產品"cdn

拓展

Spring提供了BeanFactoryPostProcessor的容器拓展機制,該機制容許咱們在容器實例化相應對象以前,對註冊到容器的BeanDefinition所保存的信息作相應的修改.

那咱們有哪些實際場景有運用到這個拓展呢?

好比咱們配置數據庫信息,常常用到佔位符

${jdbc.url}
複製代碼

BeanFactory在第一階段加載完成全部配置信息時,保存的對象的屬性信息還只是以佔位符的形式存在.這個解析的工做是在PropertySourcesPlaceholderConfigurer中作的,咱們來看看繼承體系圖就明白了.

PropertySourcesPlaceholderConfigurer實現了該接口,在進入第二階段時,已經把佔位符信息替換完成.

舒適提示:

細心的同窗可能發現PropertySourcesPlaceholderConfigurerPropertyPlaceholderConfigurer名字好像,這兩個有什麼區別?咱們來看源碼

敲黑板劃重點

爲什麼我反覆強調基礎原理,難道是爲了騙你關注一下我,多一個粉絲?由於基礎紮實,明白原理以後不少東西真的是一通百通的,尤爲了Spring Boot簡化了配置,不少問題就更考驗基礎了.我演示一個簡單的問題

首先咱們發現這個佔位符沒有被解析,若是不知道原理你可能一臉懵逼,可是看過肥朝公衆號的你,知道是缺乏PropertySourcesPlaceholderConfigurer

因而你高高興興補上了PropertySourcesPlaceholderConfigurer,發現有坑,佔位符是解析出來了,可是倒是null

而後你經過私信聯繫到了肥朝,肥朝告訴你,加上個static就能夠了.因而你一運行,果真是棒棒噠!

可是你卻百思不得其解,爲啥加上了一個static就能夠了呢?

緣由很簡單,前面都說了,這個拓展機制是在實例化對象以前,你用static修飾方法,是屬於類級別的,優先級高,天然在DataSource實例化以前就完成了這個佔位符的解析工做.

Dubbo spi中的iOC

既然是源碼解析類文章,我就儘可能避免貼大段代碼,不然還不如你直接去看.我用一個圖來粗略描述這個大體的過程

除了上一篇中對objectFactory的介紹外,從這裏咱們知道,objectFactory就是dubbo的IoC提供對象.

public <T> T getExtension(Class<T> type, String name) {
    //factories=[SpiExtensionFactory,SpringExtensionFactory]
    //遍歷獲取spi,先從SpiExtensionFactory獲取,若是沒有,再從SpringExtensionFactory獲取
    for (ExtensionFactory factory : factories) {
        T extension = factory.getExtension(type, name);
        if (extension != null) {
            return extension;
        }
    }
    return null;
}
複製代碼

SpiExtensionFactory

public <T> T getExtension(Class<T> type, String name) {
    if (type.isInterface() && type.isAnnotationPresent(SPI.class)) {
        ExtensionLoader<T> loader = ExtensionLoader.getExtensionLoader(type);
        if (loader.getSupportedExtensions().size() > 0) {
            return loader.getAdaptiveExtension();
        }
    }
    return null;
}
複製代碼

SpringExtensionFactory

public <T> T getExtension(Class<T> type, String name) {
    for (ApplicationContext context : contexts) {
        if (context.containsBean(name)) {
            //從容器中獲取注入的對象
            Object bean = context.getBean(name);
            if (type.isInstance(bean)) {
                return (T) bean;
            }
        }
    }
    return null;
}
複製代碼

dubbo在設計的時候設計了這兩種方式,可是截止2.5.4版本,SpringExtensionFactory的方式還沒有發現使用,可能像Java的保留字同樣,給之後埋下伏筆.聽說3.0版本準備出來,到時候能夠關注一下SpringExtensionFactory的使用狀況.

寫在最後

肥朝 是一個專一於 原理、源碼、開發技巧的技術公衆號,號內原創專題式源碼解析、真實場景源碼原理實戰(重點)。掃描下面二維碼關注肥朝,讓本該造火箭的你,再也不擰螺絲!

相關文章
相關標籤/搜索