簡單總結就是一種使用類名字符串來動態實例化java類的方式,也就是反射。java
(此圖來自網上,我沒有刻意去截圖)ide
而後在這個文件裏面寫入實現類函數
com.blueskykong.javaspi.serializer.KryoSerializerurl
com.blueskykong.javaspi.serializer.JavaSerializerspa
可是dubbo的SPI格式變了,也就意味着不能直接使用java SPI了code
文件的目錄類似,可是裏面的內容變爲了key-valueblog
adaptive=com.alibaba.dubbo.common.extension.factory.AdaptiveExtensionFactory
spi=com.alibaba.dubbo.common.extension.factory.SpiExtensionFactory接口
結論:所謂的這些SPI只不過是一種方式而已,最後都是反射生成類(還有classloader的問題,這裏咱們不討論),組織方式能夠隨便變,可是既然是分析dubbo,那麼這裏就看dubbo是怎麼最終實現的ssl
dubbo至關於使用了key-value的形式,用key來映射每一個類,這樣用戶就能夠在url加入這個key來實現動態加載某個類的需求,字符串
那麼爲何java SPI的方式不行:
如今使用key-value的方式已經能夠由用戶指定key去加載class,可是出於系統的考慮還有一些功能須要擴展
dubbo中負責SPI的處理的類主要是 ExtensionLoader
這裏我標註出主要的變量含義
/** * 這個三個表明須要從哪一個resource路徑下加載咱們的key-value文件 */ private static final String SERVICES_DIRECTORY = "META-INF/services/"; private static final String DUBBO_DIRECTORY = "META-INF/dubbo/"; private static final String DUBBO_INTERNAL_DIRECTORY = DUBBO_DIRECTORY + "internal/"; /** * 在註解裏面的value是可使用逗號(,)來設置多個值 */ private static final Pattern NAME_SEPARATOR = Pattern.compile("\\s*[,]+\\s*"); /** * ExtensionLoader 是每一個接口對應一個 這個map保存了接口和對應的ExtensionLoader的對應 */ private static final ConcurrentMap<Class<?>, ExtensionLoader<?>> EXTENSION_LOADERS = new ConcurrentHashMap<Class<?>, ExtensionLoader<?>>(); /** * 保存了配置文件中全部value-key之間的映射 */ private static final ConcurrentMap<Class<?>, Object> EXTENSION_INSTANCES = new ConcurrentHashMap<Class<?>, Object>(); // 以上都是靜態變量也就是是全局的 /** * 當前這個ExtensionLoader 對應的那個接口 */ private final Class<?> type; private final ExtensionFactory objectFactory; /** * value-key之間的反映射 */ private final ConcurrentMap<Class<?>, String> cachedNames = new ConcurrentHashMap<Class<?>, String>(); /** * 配置文件中key-value之間的映射 value指的是類class */ private final Holder<Map<String, Class<?>>> cachedClasses = new Holder<Map<String, Class<?>>>(); /** * 這裏保存着這個接口的實現類含有@Activate註解 */ private final Map<String, Activate> cachedActivates = new ConcurrentHashMap<String, Activate>(); /** * 這個接口下 key-value的映射 value指的是實例 */ private final ConcurrentMap<String, Holder<Object>> cachedInstances = new ConcurrentHashMap<String, Holder<Object>>(); /** * 適配類的實例 */ private final Holder<Object> cachedAdaptiveInstance = new Holder<Object>(); /*** * 這個接口的適配類 也就是註解@Adaptive的註解加載類的這個類就是適配類 所謂的適配類 就是實現根據url裏面的參數 * 來決定使用這個接口的哪一個子類 */ private volatile Class<?> cachedAdaptiveClass = null; /** * SPI註解裏面value 做爲這個接口的默認加載類 */ private String cachedDefaultName;
總結一下:
在key-value映射中,會分爲包裝類和正常類,所謂的包裝類就是利用裝飾器模式,來實現對原功能進行一些額外的處理,識別方式是按照是否有一個構造方法含有這個接口做爲參數爲標識
這裏的注入是指對接口裏面的變量進行注入實例
還在更新......