Dubbo的SPI
阿新 • • 發佈:2020-09-15
從自定義Dubbo的rpc協議來學習Dubbo的SPI
SPI 全稱為 Service Provider Interface
JDK的SPI實現
public class SpiTest { public static void main(String[] args) { // 註解1 ServiceLoader<Human> load = ServiceLoader.load(Human.class); // 註解2 Iterator<Human> iterator = load.iterator(); // 註解3 while (iterator.hasNext()) { // 註解4 Human next = iterator.next(); System.out.println(next.getName()); } } }
public final class ServiceLoader<S> implements Iterable<S> { //掃描目錄字首 private static final String PREFIX = "META-INF/services/"; // 被載入的類或介面 private final Class<S> service; // 用於定位、載入和例項化實現方實現的類的類載入器 private final ClassLoader loader; // 上下文物件 private final AccessControlContext acc; // 按照例項化的順序快取已經例項化的類 private LinkedHashMap<String, S> providers = new LinkedHashMap<>(); // 懶查詢迭代器 private java.util.ServiceLoader.LazyIterator lookupIterator; // 私有內部類,提供對所有的service的類的載入與例項化 private class LazyIterator implements Iterator<S> { Class<S> service; ClassLoader loader; Enumeration<URL> configs = null; String nextName = null; //... private boolean hasNextService() { if (configs == null) { try { //獲取目錄下所有的類 String fullName = PREFIX + service.getName(); if (loader == null) configs = ClassLoader.getSystemResources(fullName); else configs = loader.getResources(fullName); } catch (IOException x) { //... } //.... } } private S nextService() { String cn = nextName; nextName = null; Class<?> c = null; try { //反射載入類 c = Class.forName(cn, false, loader); } catch (ClassNotFoundException x) { } try { //例項化 S p = service.cast(c.newInstance()); //放進快取 providers.put(cn, p); return p; } catch (Throwable x) { //.. } //.. } } }
註解1
load方法關注最後一步關注例項化一個LazyIterator例項,賦值給變數lookupIterator
註解2
iterator方法就是例項化了一個匿名類
註解3
hasNext方法最終呼叫的就是這裡,從中我們可以看到fullName的PREFIX就是我們在resources下建立的資料夾META-INF/services/與service的全路徑名字拼接,所以我們建立的檔案是固定的,然後通過getResources獲取內容,nextElement讀取下一個
註解4
nextName在我們執行hasNext的時候已經賦上值了,這裡我們通過Class.foorName進行例項化,但是這時候先不初始化,接下來需要判斷他的繼承關係,接著通過newInstance例項化放入到providers這個快取map中
JDBC的SPI
我們看到JDBC就使用了SPI的技術,而且使用的就是JDK原生的方式
Dubbo的SPI
Jdk的SPI就是一個List,你只能通過Iterator進行遍歷獲取你想要的元素,Dubbo自定義了自己的SPI,使用的是map這種K/V結構的資料結構,這樣方便快速定位到想要的實現類。
dubbo的spi原理我覺得官網講的不錯,直接貼連結dubbo-spi原理
dubbo的spi大大提高了dubbo的靈活性,假如你對註冊中心不滿意,或者你對rmi協議想定製了,這時候你只需要自定義自己的模組即可
然後你在配置檔案中直接使用你自定義的名字即可,這裡的csrmi其實就是你在META-INF/dubbo/internal定義的檔案中的key