Dubbo解析(一)-内核实现之SPI机制(上)

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

  1. 在classpath的META-INF/services/目录下建立名称为服务接口的全限定名(package+className)的文件,文件编码必须为UTF-8,文件内容为服务接口实现类的全限定名,一个文件内能够定义多个实现类,按行分开便可。
  2. 服务接口实现类必须有一个无参的构造方法。
  3. 使用java.util包下的ServiceLoader类的load方法动态加载接口的实现类。

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

相关文章
相关标签/搜索