Dubbo SPI
基于Java的SPI机制,Dubbo在其思想的基础上自己实现了一套SPI机制,弥补了Java SPI的缺点,并进行了相应的扩展。
1. Dubbo SPI 改进了 Java SPI 的以下问题:
Java SPI
是一次性加载、实例化所有的扩展点实现,不支持根据key
值去加载、实例化指定的扩展点实现。Java SPI
不支持IOC、AOP
,Dubbo SPI
则通过自动包装、自动装配等特性实现了IOC、AOP
。ServerLoader
在加载类的过程中如果出现异常无法加载没有相关的异常抛出,导致一旦出现问题需要花时间进行定位。
2. Dubbo SPI 的三个特性
2.1. 自动包装
基于装饰器设计模式,通过创建、配置Wrapper类,从而实现对实现类的增强。我们可以将一些公共的逻辑放置在Wrapper类中,从而实现了公共逻辑与业务逻辑的解耦,同时也更易于扩展和维护。
2.2. 自动装配
类似于Spring的IOC依赖注入的功能,在加载扩展点的实现类时,会遍历所有setter方法,尝试着为其注入其他扩展点依赖。
2.3. 自适应
Dubbo使用URL对象传递配置信息,通过在URL对象中配置对应的key-value键值对,从而实现在调用相应方法时能够通过URL中的配置匹配对应的扩展点实现。
2.4. 自动激活
当我们想通过一个配置激活多个扩展点实现时,可以通过@Activate注解来实现,从而简化了配置。
3. 代码示例:
3.1. 车辆接口
package com.dubbo.service;
import org.apache.dubbo.common.extension.SPI;
@SPI
public interface ICarService {
void speed();
}
3.2. 车辆接口的两个实现类AudiService
、BmwService
package com.dubbo.service.impl;
import com.dubbo.service.ICarService;
public class AudiService implements ICarService {
@Override
public void speed() {
System.out.println("audi drive speed 100KM/H");
}
}
public class BMWService implements ICarService {
@Override
public void speed() {
System.out.println("bmw drive speed 200KM/H");
}
}
3.3. 配置文件
resources\META-INF\services\com.dubbo.service.ICarService
audi=com.dubbo.service.impl.AudiService
bmw=com.dubbo.service.impl.BMWService
3.4. 测试方法
private static void dubboSpi() {
ExtensionLoader<ICarService> extensionLoader = ExtensionLoader.getExtensionLoader(ICarService.class);
ICarService carService = extensionLoader.getExtension("audi");
carService.speed();
}
// 输出
audi drive speed 100KM/H
4. 源码解析
4.1 获取扩展点加载器
Main方法
ExtensionLoader.getExtensionLoader(ICarService.class);
ICarService carService = extensionLoader.getExtension("audi");
org.apache.dubbo.common.extension.ExtensionLoader
// key:扩展点接口-扩展点加载器
private static final ConcurrentMap<Class<?>, ExtensionLoader<?>> EXTENSION_LOADERS = new ConcurrentHashMap<>();
// 获取扩展点加载器
public static <T> ExtensionLoader<T> getExtensionLoader(Class<T> type) {
...
// 尝试从缓存中获取扩展点加载器
ExtensionLoader<T> loader = (ExtensionLoader<T>) EXTENSION_LOADERS.get(type);
if (loader == null) {
// 如果未能从缓存中获取到,则创建一个新的扩展点加载器放入缓存中
EXTENSION_LOADERS.putIfAbsent(type, new ExtensionLoader<T>(type));
loader = (ExtensionLoader<T>) EXTENSION_LOADERS.get(type);
}
// 返回扩展点加载器
return loader;
}
获取到扩展点加载器后,调用扩展点加载器的getExtension
方法获取扩展点实现对象
public T getExtension(String name) {
if (StringUtils.isEmpty(name)) {
throw new IllegalArgumentException("Extension name == null");
}
// 如果传入name为true,则获取默认扩展实现
if ("true".equals(name)) {
return getDefaultExtension();
}