dubbo SPI功能解析(一)

鄧橋發表於2018-11-15

SPI配置說明

如果需要擴充套件Dubbo Protocol介面實現,需要在自己的擴充套件jar中新增文字檔案 META-INF/dubbo/com.alibaba.dubbo.rpc.Protocol ,檔案內容為

xxx=com.alibaba.xxx.XxxProtocol
複製程式碼

實現類為

package com.alibaba.xxx;
 
import com.alibaba.dubbo.rpc.Protocol;
 
public class XxxProtocol implements Protocol { 
    // ...
}
複製程式碼

SPI的擴充套件配置都是通過配置標籤屬性來實現的

<dubbo:protocol name="xxx" />
複製程式碼

SPI特性

SPI自動包裝SPI Auto Wrap

package com.alibaba.xxx;
 
import com.alibaba.dubbo.rpc.Protocol;
 
public class XxxProtocolWrapper implements Protocol {
    Protocol impl;
 
    public XxxProtocolWrapper(Protocol protocol) { impl = protocol; }
 
    //after interface method is executed,the method in extension will be executed
    public void refer() {
        //... some operation
        impl.refer();
        // ... some operation
    }
 
    // ...
}
複製程式碼

SPI包裝器實現類也實現了SPI介面,包裝器類名必須以Wrapper結尾,構造器方法需要傳入真正的SPI實現類,當通過ExtensionLoader SPI實現類載入器載入SPI實現類時,會自動返回具體實現類的包裝實現,通過這種方式型別了類似Spring AOP的功能。包裝器實現類可以有多個,這樣可以實現鏈式結構。

最典型的實現見ProtocolFilterWrapper將Protocol協議生成的Invoker實現包裝了一層Filter過濾器鏈

SPI依賴注入(自動載入)

public interface CarMaker {
    Car makeCar();
}
 
public interface WheelMaker {
    Wheel makeWheel();
}
複製程式碼

假設有兩個SPI介面CarMaker,WheelMaker如上 CarMaker implementation:

public class RaceCarMaker implements CarMaker {
    WheelMaker wheelMaker;
 
    public setWheelMaker(WheelMaker wheelMaker) {
        this.wheelMaker = wheelMaker;
    }
 
    public Car makeCar() {
        // ...
        Wheel wheel = wheelMaker.makeWheel();
        // ...
        return new RaceCar(wheel, ...);
    }
}
複製程式碼

當通過ExtensionLoader來載入CarMaker實現時,會自動載入WheelMaker的實現類設定到wheelMaker的屬性中實現依賴注入的功能,如果WheelMaker有多個實現類,會建立WheelMaker自適應實現作為實現類。如果只有一個實現類既為該實現類。

SPI自適應實現

public interface CarMaker {
    Car makeCar(URL url);
}
 
public interface WheelMaker {
    Wheel makeWheel(URL url);
}

public class RaceCarMaker implements CarMaker {
    WheelMaker wheelMaker;
 
    public setWheelMaker(WheelMaker wheelMaker) {
        this.wheelMaker = wheelMaker;
    }
 
    public Car makeCar(URL url) {
        // ...
        Wheel wheel = wheelMaker.makeWheel(url);
        // ...
        return new RaceCar(wheel, ...);
    }
}
複製程式碼

可以看到SPI介面實現類方法都增加了URL引數,最關鍵的Wheel wheel = wheelMaker.makeWheel(url); wheelMaker自適應類實現了一個薄薄的代理層,會根據Url物件中預定義的key,預設使用SPI的類名簡稱 url.get("wheelMaker")獲取真正的實現名稱,然後通過ExtensionLoader獲取真實實現名對應的實現類。 dubbo將XML配置中所有的資訊都封裝在URL中,自適應實現類通過修改XML配置切換具體實現類的。

相關文章