所谓Dubbo的内核是指,Dubbo中所有功能都是基于内核完成的,都是由内核作为基础;dubbo的内核包含四部分,SPI、AOP、IOC与Compiler,后三部分的实现都基于SPI,所以说SPI是内核的内核;
1.1 JDK的SPI机制
SPI,Service Provider Interface,服务提供者接口,是一种服务发现机制;
1.2 JDK的SPI规范
-
接口名:可随意定义(符合命名约定)
-
实现类名:可随意定义(约定为serviceInterfaceIMPL)
-
提供者配置文件路径:其查找的目录为META-INF/service
-
提供者配置文件名称:接口的全限定性类名,没有扩展名
-
提供者配置文件内容:该接口的所有实现类的全限定性类名写入到该文件中,一个类名占一行
1.3 示例
(1)定义接口
public interface SomeService {
void doSome();
}
(2)定义接口配置文件路径及文件
#文件内容
com.zxy.service.impl.OneServiceImpl
com.zxy.service.impl.TwoServiceImpl
(3)定义两个实现类
public class OneServiceImpl implements SomeService{
public void doSome() {
// TODO Auto-generated method stub
System.out.println("执行OneServiceImpl中的doSome()");
}
}
public class TwoServiceImpl implements SomeService{
public void doSome() {
// TODO Auto-generated method stub
System.out.println("执行TwoServiceImpl中的doSome()");
}
}
(4)定义测试类
/**
* 需要调用两个实现类的doSome()方法,并且实现类不出现在此
*
*/
public class SPITest {
public static void main(String[] args) {
// TODO Auto-generated method stub
ServiceLoader<SomeService> loader = ServiceLoader.load(SomeService.class);
Iterator<SomeService> iterator = loader.iterator();
while(iterator.hasNext()) {
//运行到此处是会加载具体接口的实现类
SomeService service = iterator.next();
service.doSome();
}
}
}
1.4 JDK-SPI的弊端
当接口的实现类存在多个,而调用者只想调用其中某一个实现的时候,就出现了问题,JDK的SPI机制是必须将所有的实现类加载进来,然后做判断调用,但是所有的实现类已经全部实例化并且加载到了内存中;
2.Dubbo的SPI
Dubbo并未直接使用JDK的SPI,而是在其基础上进行了改进;
2.1 规范说明
-
接口名:可以随意定义;
-
实现类名:在接口名前添加一个用于表示自身功能的“标示前缀”字符串;
-
提供者配置文件路径:依次查找目录为
META-INF/dubbo/internal
META-INF/dubbo
META-INF/services
-
提供者配置文件名称:接口的全限定性类名,无需扩展名;
-
提供者配置文件内容:文件的内容为key=value形式,value为该接口的实现类的全限定类性名,key可以随意,规范约定一般为该实现类的“标示前缀”(首字母小写),一个类名占一行;
-
提供者加载:ExtensionLoader类相当于JDK SPI中的ServiceLoader类,用于加载提供者配置文件中所有的实现类,并创建相应的实例;
ExtensionLoader有type类型概念,其内部的getExtensionLoader静态方法,有一个type参数,用此方法获取的实例,只能获取传入参数类型的SPI,也就是不同的SPI接口有不同的ExtensionLoader实例,这就是微服务+插件的一种思想;
2.2 Dubbo的SPI示例
实现一个下单功能,其支付方式支持支付宝与微信两种,即要定义一个SPI接口,其存在两个扩展类;
(1)创建工程dubbospi导入dubbo依赖
<!-- dubbo依赖 -->
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo</artifactId>
<version>2.7.0</version>
</dependency>
(2)定义Order接口
/**
* SPI标签,设置默认为wechat微信支付
*/
@SPI("wechat")
public interface Order {
String way();
}
(3)定义接口配置文件路径及文件
#dubbo允许多个key
wechat,wechatdetry,wechatproty=com.zxy.spi.extension.WeChatOrder
alipay=com.zxy.spi.extension.AlipayOrder
(4)定义实现类
public class AlipayOrder implements Order{
public String way() {
// TODO Auto-generated method stub
System.out.println("---支付宝way()---");
return "支付宝支付方式";
}
}
public class WeChatOrder implements Order{
public String way() {
System.out.println("---微信way()---");
return "微信支付方式";
}
}
(5)定义测试类
public class OrderTest {
public static void main(String[] args) {
//获取SPI接口Order的扩展加载实例
ExtensionLoader<Order> loader = ExtensionLoader.getExtensionLoader(Order.class);
//获取指定名的扩展类
Order alipay = loader.getExtension("alipay");
System.out.println(alipay.way());
Order wechat = loader.getExtension("wechat");
System.out.println(wechat.way());
Order wechatdetry = loader.getExtension("wechatdetry");
System.out.println(wechatdetry.way());
Order wechatproty = loader.getExtension("wechatproty");
System.out.println(wechatproty.way());
}
}