1. 程式人生 > >dubbo源碼解析-spi(3)

dubbo源碼解析-spi(3)

做的 property 部分 修飾 末尾 not clas ioc cto

前言

在上一篇的末尾,我們提到了dubbo的spi中增加了IoC和AOP的功能.那麽本篇就講一下這個增加的IoC,spi部分預計會有四篇,因為這東西實在是太重要了.溫故而知新,我們先來回顧一下,我們之前都講了什麽.

  • spi(1) 主要講了spi的基本概念,簡單的入門,並以spi為線索講解了雙親委托模式的弊端以及解決方案
  • spi(2) 主要以dubbo改進了jdk的spi為線索,重點講分析問題的思路,從實際案例實戰從哪裏著手分析問題這個大家最喜歡問的問題.

提到IoC,大家第一個想到的就是Spring,所以Spring的IoC也是本篇的一大重點內容.當然畢竟主題是dubbo,所以對於Spring內容,將與dubbo結合,以短小精幹,但是又不缺乏深度的介紹.(後期如果大家有需要,也可以開展Spring源碼專題)

看到這裏可能有同學就會問,肥朝你不是寫dubbo源碼解析的嗎,為什麽還要講Spring呢?dubbo中涉及到很多的邊緣知識,其中包括Spring、Netty、Zookeeper等等,我希望的是,大家能通過學習dubbo為主線,全面綜合的提高自己,而不是為了看源碼而看源碼,也不是為了面試而看源碼.

插播面試題
你提到了dubbo中spi也增加了IoC,那你先講講Spring的IoC,然後再講講dubbo裏面又是怎麽做的
Spring的IoC
容器
Spirng的IoC容器主要有兩種,即BeanFactory和ApplicationContext

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

另外ApplicationContext在加載的時候就會創建所有的bean(Web應用推薦),BeanFactory需要等到拿bean的時候才會創建bean(桌面應用推薦).所以,我們一般使用ApplicationContext

總體流程
實現IoC的過程,總體可以分為兩步,如下圖

技術分享圖片

容器啟動階段

技術分享圖片

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

Bean實例化階段

技術分享圖片

拓展

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

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

比如我們配置數據庫信息,經常用到占位符

${jdbc.url}

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

技術分享圖片

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

溫馨提示:

細心的同學可能發現PropertySourcesPlaceholderConfigurer和PropertyPlaceholderConfigurer名字好像,這兩個有什麽區別?我們來看源碼

技術分享圖片

敲黑板劃重點

為何我反復強調基礎、原理,難道是為了騙你關註一下我,多一個粉絲?因為基礎紮實,明白原理之後很多東西真的是一通百通的,尤其了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的使用情況.

Ref:

https://www.jianshu.com/p/718acbda838c

dubbo源碼解析-spi(3)