前面有说到 Java SPI 的介绍与使用方法, 而本篇要说的 Dubbo SPI 是基于 Java SPI 的一个升级与改造(改善了部分缺点,增长了几个新玩法)。具体内容能够去看官网 Dubbo-SPI 部分。html
本文主要来说下 Dubbo SPI 的部分使用方法。java
另外,后续文章会补齐 Dubbo SPI 的其余用法以及 Dubbo SPI 部分的源码解析。apache
固然 官网 也有 Dubbo SPI 的使用说明与源码导读,能够自行选择。segmentfault
Dubbo SPI 的使用方法具体分为如下部分:app
本文先来介绍前两种使用方法,建议先看下 Java SPI 的介绍与使用方法,了解下 SPI 的机制及用途。ide
从这点来看,Dubbo SPI 从使用上与 JAVA SPI 并没有很大差别。函数
主要区别在于:this
JDK 标准的 SPI 会一次性实例化扩展点全部实现,若是有扩展实现初始化很耗时,但若是没用上也加载,会很浪费资源。
而 Dubbo SPI 能够选择性实例化某个扩展接口实现类。spa
下面来看下写法上的差异,具体代码以下:.net
注解中的 value 为 步骤 1.3 中配置的" 接口实现类的名称",好比@SPI("helloService")
, 至关于指定默认的扩展实现类为 com.nimo.service.impl.HelloServiceImpl
// 差异一:Dubbo 须要 SPI 注解 @SPI public interface HelloService { void sayHello(String name); }
public class HelloServiceImpl implements HelloService { @Override public void sayHello(String name) { System.out.println("hello, " + name); } }
# 差异二:文件夹命名方式不一样,以及文件内容格式不一样 META-INF\dubbo\com.nimo.service.HelloService (以接口名全路径命名)
文件内容为:key-value 形式
helloService=com.nimo.service.impl.HelloServiceImpl # 能够有多个实现 helloService1=com.nimo.service.impl.HelloServiceImpl1 helloService2=com.nimo.service.impl.HelloServiceImpl2 省略。。。。
public class App { public static void main( String[] args ) { // 差异三: API 不一样 ExtensionLoader<HelloService> extensionLoader = ExtensionLoader.getExtensionLoader(HelloService.class); // 经过指定扩展类名称y ,获取对应实例化对象 // 这里 extensionLoader 能够把它看成一个 map // 若是参数为 ”true“,会加载默认的扩展类 HelloService helloService = extensionLoader.getExtension("helloService"); helloService.sayHello("xiaoming"); } }
运行结果:
hello, xiaoming
其实 ExtensionLoader 内部确实有不少 ConcurrentHashMap 容器,它们各司其职,具体的后面源码篇会详细说。
ExtensionLoader 在加载扩展点时,若是加载到的扩展点有拷贝构造函数,则断定为扩展点 Wrapper 类。
这个有点相似 AOP,看下具体代码和效果就明白了。
// 实现扩展接口以及以下模板的构造方法 public class HelloServiceImplWrapper implements HelloService { private HelloService helloService; public HelloServiceImplWrapper(HelloService helloService){ this.helloService = helloService; } @Override public void sayHello(String name) { // 这里至关于对原有的 Service 进行了加强 System.out.println("before"); helloService.sayHello(name); System.out.println("after"); } }
// 第二步,在原有增长部份内容,更改后以下: helloService=com.nimo.service.impl.HelloServiceImpl helloService=com.nimo.service.impl.HelloServiceImplWrapper
运行结果:
before hello, xiaoming after
本文先引入 Dubbo SPI 的基本使用,而后介绍了其中一个高级玩法-扩展点自动包装,
它的做用正如官网所说,相似一个 AOP。
另外,经过 ExtensionLoader 获取扩展点的实现类的具体实例时,大体伪代码以下所示:
HelloService helloService = new HelloServiceImpl(); if (wrapper 存在) { helloService = wrapper; } return helloService;
最后调用 sayHello
方法时,就是调用的 wrapper.sayHello()