Dubbo原始碼分析之SPI(二)
一、概述
本篇文章是dubbo SPI原始碼分析的第二篇,接著第一篇繼續分析dubbo SPI的內容,我們主要介紹 getDefaultExtension() 獲取預設擴充套件點方法。
由於此方法比較簡單,我們略過示例部分,直接分析原始碼。
二、原始碼分析
獲取預設擴充套件方法getDefaultExtension()是一個public、可對外提供呼叫的方法。我們知道,dubbo中擴充套件點介面必須要有@SPI註解修飾,@SPI註解程式碼如下:
1 @Documented 2 @Retention(RetentionPolicy.RUNTIME) 3 @Target({ElementType.TYPE}) 4 public @interface SPI { 5 6 /** 7 * default extension name 8 */ 9 String value() default ""; 10 11 }
註解可以修飾類和介面,同時提供 一個預設為空的value欄位。
這個value欄位 就是本篇文章要介紹的預設擴充套件實現。
現在我們來看getDefaultExtension()方法內部:
1 public T getDefaultExtension() { 2 getExtensionClasses(); 3 // cachedDefaultName為@SPI中的value 4 if (null == cachedDefaultName || cachedDefaultName.length() == 0 || "true".equals(cachedDefaultName)) { 5 return null; 6 } 7 return getExtension(cachedDefaultName); 8 }
第二行方法 getExtensionClasses()是載入配置文字檔案,獲取配置的擴充套件點實現類,方法執行完,會把配置文字檔案的key和擴充套件點實現類的Class物件儲存在cachedClasses 成員變數中,這個我們在第一篇已經介紹過。
接下來就是方法的關鍵點,成員變數cachedDefaultName 的判斷了,如果cachedDefaultName 為空或為”true“ 直接返回 null,如果cachedDefaultName 不為空,則呼叫getExtension(..)方法,返回擴充套件點實現類物件。這個方法我們在第一篇也已經介紹了。現在我們只需要分析cachedDefaultName的賦值點 就ok 了。
成員變數cachedDefaultName 我們在第一篇有介紹到,不知道大家是否還有印象,我們現在看看變數定義:
1 // SPI()內value,預設的介面實現 2 private String cachedDefaultName;
私有的字串變數。
變數cachedDefaultName的賦值,我們先提前介紹下,其實就是在載入配置文字檔案的過程中進行的,具體的方法呼叫鏈為:
1 getDefaultExtension() -->getExtensionClasses()-->loadExtensionClasses()
這幾個方法我們都有介紹,我們現在看看loadExtensionClasses():
1 private Map<String, Class<?>> loadExtensionClasses() { 2 // 獲取註解 SPI的介面 3 // type為傳入的擴充套件介面,必須有@SPI註解 4 final SPI defaultAnnotation = type.getAnnotation(SPI.class); 5 // 獲取預設擴充套件實現value,如果存在,賦值給cachedDefaultName 6 if (defaultAnnotation != null) { 7 String value = defaultAnnotation.value(); 8 if ((value = value.trim()).length() > 0) { 9 // @SPI value 只能是一個,不能為逗號分割的多個 10 // @SPI value為預設的擴充套件實現 11 String[] names = NAME_SEPARATOR.split(value); 12 if (names.length > 1) { 13 throw new IllegalStateException("more than 1 default extension name on extension " + type.getName() + ": " + Arrays.toString(names)); 14 } 15 if (names.length == 1) 16 cachedDefaultName = names[0]; 17 } 18 } 19 // 載入三個目錄配置的擴充套件類 20 Map<String, Class<?>> extensionClasses = new HashMap<String, Class<?>>(); 21 // META-INF/dubbo/internal 22 loadDirectory(extensionClasses, DUBBO_INTERNAL_DIRECTORY); 23 // META-INF/dubbo 24 loadDirectory(extensionClasses, DUBBO_DIRECTORY); 25 // META-INF/services/ 26 loadDirectory(extensionClasses, SERVICES_DIRECTORY); 27 return extensionClasses; 28 }
沒錯,對cachedDefaultName的賦值,僅此一出。
cachedDefaultName的內容就是解析@SPI註解的value內容。此處賦值後,getDefaultExtension()方法的返回就是根據這個值進行擴充套件點獲取並返回的。
三、總結
獲取預設擴充套件點的方法getDefaultExtension() 邏輯很簡單,就是解析出註解@SPI的value內容,通過前一篇介紹的getExtension(..)方法進行擴充套件點獲取。如果@SPI沒有配置value或者設定的是”true“,getDefaultExtension()方法返回的就是null。
&n