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机制又增长了哪些呢,下一章见。源码