Dubbo採用微內核+插件的方式,使得設計優雅,擴展性強。但也給源碼的學習帶來了必定的困難,初看者經常迷失在找不到方法的具體實現。在學習dubbo源碼前,必需要了解其內核的SPI機制.什麼是SPI,它是JDK內置的一種服務發現機制,全稱是Service Provider Interface(服務提供者接口),也就是尋找接口服務的提供者的一種規範。java
舉個例子,你在淘寶上賣東西,客戶下單後要發快遞,通常你會找快遞公司幫你運輸。快遞公司有不少家,不一樣的快遞公司提供的服務也不一樣,好比順豐可能就快一點,韻達可能就慢一點。發快遞就是一個接口服務,而真正的實現由不一樣的快遞公司來完成。ide
定義一個發快遞的接口學習
package com.lntea.dubbo.demo.spi; public interface Delivery { void deliveryProduct(String productName); }
有兩個不一樣的實現編碼
// 順豐 package com.lntea.dubbo.demo.spi; public class ShunFengDelivery implements Delivery{ public void deliveryProduct(String productName) { System.out.println("你的" + productName + "到家了,順豐快遞爲您服務"); } } // 韻達 package com.lntea.dubbo.demo.spi; public class YunDaDelivery implements Delivery{ public void deliveryProduct(String productName) { System.out.println("你的" + productName + "到家了,韻達快遞爲您服務"); } }
由於快遞公司是第三方,咱們定義快遞接口服務時,根本不知道發快遞的究竟是哪家公司。JDK的SPI機制就定義了一些規範,來幫助咱們尋找服務的提供者實現:spa
按照JDK的SPI機制完成發快遞的代碼插件
package com.lntea.dubbo.demo.spi; import java.util.Iterator; import java.util.ServiceLoader; import org.junit.Test; public class DeliveryTest { @Test public void testDeliveryProduct(){ String productName = "Iphone X"; delivery(productName); } private void delivery(String productName) { ServiceLoader<Delivery> loader = ServiceLoader.load(Delivery.class); Iterator<Delivery> iterator = loader.iterator(); while(iterator.hasNext()){ Delivery delivery = iterator.next(); delivery.deliveryProduct(productName); } } } 輸入結果以下: 你的Iphone X到家了,順豐快遞爲您服務 你的Iphone X到家了,韻達快遞爲您服務
ServiceLoader實現了Iterable接口,能夠遍歷每個服務提供者,並調用它的服務。結果就是客戶買了一個Iphone X, 結果你快遞了兩個給人。固然淘寶賣家不會這麼傻,通常都會默認一家快遞公司,或者客戶能夠指定其餘的快遞公司,咱們就須要接口中定義一個匹配方法。設計
public interface Delivery { // 公司名稱是否匹配 boolean match(String companyName); void deliveryProduct(String productName); }
那順豐和韻達在服務實現類中就要匹配本身的公司名稱code
// 順豐 public class ShunFengDelivery implements Delivery{ public boolean match(String companyName) { return "sf".equals(companyName); } public void deliveryProduct(String productName) { System.out.println("你的" + productName + "到家了,順豐快遞爲您服務"); } } // 韻達 public class YunDaDelivery implements Delivery{ public boolean match(String companyName) { return "yd".equals(companyName); } public void deliveryProduct(String productName) { System.out.println("你的" + productName + "到家了,韻達快遞爲您服務"); } }
發快遞的代碼也須要變動接口
public class DeliveryTest { @Test public void testDeliveryProduct(){ String productName = "Iphone X"; String companyName = "sf"; delivery(companyName, productName); } private void delivery(String companyName, String productName) { ServiceLoader<Delivery> loader = ServiceLoader.load(Delivery.class); Iterator<Delivery> iterator = loader.iterator(); while(iterator.hasNext()){ Delivery delivery = iterator.next(); // 匹配指定的快遞公司 if(delivery.match(companyName)){ delivery.deliveryProduct(productName); break; } } } } 輸出結果: 你的Iphone X到家了,順豐快遞爲您服務
以上介紹了JDK的SPI機制,而Dubbo內核對於擴展點的加載方式就是從JDK的SPI機制加強而來的。那麼JDK的SPI機制有什麼缺點呢,Dubbo的SPI機制又增長了哪些呢,下一章見。源碼