在上一篇的末尾,咱們提到了dubbo
的spi
中增長了IoC
和AOP
的功能.那麼本篇就講一下這個增長的IoC
,spi
部分預計會有四篇,由於這東西實在是過重要了.溫故而知新,咱們先來回顧一下,咱們以前都講了什麼.java
從Dubbo內核聊聊雙親委派機制 主要講了spi的基本概念,簡單的入門,並以spi
爲線索講解了雙親委託模式
的弊端以及解決方案面試
Dubbo和JDK的SPI究竟有何區別? 主要以dubbo改進了jdk的spi
爲線索,重點講分析問題的思路,從實際案例實戰從哪裏着手分析問題
這個你們最喜歡問的問題.數據庫
提到IoC
,你們第一個想到的就是Spring
,因此Spring的IoC
也是本篇的一大重點內容.固然畢竟主題是dubbo
,因此對於Spring
內容,將與dubbo結合,以短小精幹,可是又不缺少深度的介紹.(後期若是你們有須要,也能夠開展Spring源碼專題)學習
看到這裏可能有同窗就會問,肥朝你不是寫dubbo源碼解析的嗎,爲何還要講Spring呢?dubbo中涉及到不少的邊緣知識,其中包括Spring
、Netty
、Zookeeper
等等,我但願的是,你們能經過學習dubbo爲主線,全面綜合的提升本身,而不是爲了看源碼而看源碼,也不是爲了面試而看源碼.url
spi
也增長了IoC
,那你先講講Spring的IoC
,而後再講講dubbo裏面又是怎麼作的Spirng的IoC容器主要有兩種,即BeanFactory
和ApplicationContext
spa
BeanFactory
是Spring中最底層的接口,只提供了最簡單的IoC
功能,負責配置,建立和管理bean.ApplicationContext
繼承了BeanFactory
,擁有了基本的IoC
功能外,還支持
另外ApplicationContext
在加載的時候就會建立全部的bean(Web應用推薦),BeanFactory
須要等到拿bean的時候纔會建立bean(桌面應用推薦).因此,咱們通常使用ApplicationContext
設計
實現IoC的過程,整體能夠分爲兩步,以下圖3d
該階段至關於"根據圖紙裝配成生產線",也就是對象管理信息的收集.code
該階段至關於"根據生產線來生產具體產品"cdn
Spring提供了BeanFactoryPostProcessor
的容器拓展機制,該機制容許咱們在容器實例化相應對象以前,對註冊到容器的BeanDefinition
所保存的信息作相應的修改.
那咱們有哪些實際場景有運用到這個拓展
呢?
好比咱們配置數據庫信息,常常用到佔位符
${jdbc.url}
複製代碼
當BeanFactory
在第一階段加載完成全部配置信息時,保存的對象的屬性信息還只是以佔位符的形式存在.這個解析的工做是在PropertySourcesPlaceholderConfigurer
中作的,咱們來看看繼承體系圖就明白了.
PropertySourcesPlaceholderConfigurer
實現了該接口,在進入第二階段時,已經把佔位符信息替換完成.
舒適提示:
細心的同窗可能發現PropertySourcesPlaceholderConfigurer
和PropertyPlaceholderConfigurer
名字好像,這兩個有什麼區別?咱們來看源碼
爲什麼我反覆強調基礎
、原理
,難道是爲了騙你關注一下我,多一個粉絲?由於基礎紮實,明白原理以後不少東西真的是一通百通的,尤爲了Spring Boot
簡化了配置,不少問題就更考驗基礎了.我演示一個簡單的問題
首先咱們發現這個佔位符沒有被解析,若是不知道原理你可能一臉懵逼,可是看過肥朝公衆號的你,知道是缺乏PropertySourcesPlaceholderConfigurer
因而你高高興興補上了PropertySourcesPlaceholderConfigurer
,發現有坑,佔位符是解析出來了,可是倒是null
而後你經過私信聯繫到了肥朝,肥朝告訴你,加上個static
就能夠了.因而你一運行,果真是棒棒噠!
可是你卻百思不得其解,爲啥加上了一個static
就能夠了呢?
緣由很簡單,前面都說了,這個拓展機制是在實例化對象以前
,你用static
修飾方法,是屬於類級別的,優先級高,天然在DataSource實例化以前就完成了這個佔位符的解析工做.
既然是源碼解析類文章,我就儘可能避免貼大段代碼,不然還不如你直接去看.我用一個圖來粗略描述這個大體的過程
除了上一篇中對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
的使用狀況.
肥朝 是一個專一於 原理、源碼、開發技巧的技術公衆號,號內原創專題式源碼解析、真實場景源碼原理實戰(重點)。掃描下面二維碼關注肥朝,讓本該造火箭的你,再也不擰螺絲!