1. 程式人生 > >Dubbo原始碼分析之SPI(二)

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