Dubbo SPI
简介
SPI 全称为 Service Provider Interface,是一种服务发现机制。SPI 的本质是将接口实现类的全限定名配置在文件中,并由服务加载器读取配置文件,加载实现类。这样可以在运行时,动态为接口替换实现类。正因此特性,我们可以很容易的通过 SPI 机制为我们的程序提供拓展功能。SPI 机制在第三方框架中也有所应用,比如 Dubbo 就是通过 SPI 机制加载所有的组件。不过,Dubbo 并未使用 Java 原生的 SPI 机制,而是对其进行了增强,使其能够更好的满足需求。在 Dubbo 中,SPI 是一个非常重要的模块。基于 SPI,我们可以很容易的对 Dubbo 进行拓展。如果大家想要学习 Dubbo 的源码,SPI 机制务必弄懂。 摘自dubbo 官方文档
能够被扩展的接口必须要有这样的标记->@SPI{} (Dubbo自定义的注解)
@SPI(‘value’) 表示当前扩展点的默认实现
静态扩展点
1、解析 load 指定路径下对应的SPI 扩展点的实现,缓存到hashmap中,key 就是配置文件中定义的name,value就是class
2、getExtension(‘name’)->EXTENSION_INSTANCES.get(‘name’) 获取 instance
依赖注入
Spring中依赖注入的方式:
- 接口注入
- setter注入
- 构造方法注入
Dubbo 依赖注入的方式:
set方法进行注入
如果当前的扩展点中依赖其他的扩展点,会进行依赖注入
public class ZookeeperDynamicConfigurationFactory extends AbstractDynamicConfigurationFactory {
//扩展点接口
private ZookeeperTransporter zookeeperTransporter;
//通过set注入
public void setZookeeperTransporter(ZookeeperTransporter zookeeperTransporter) {
this.zookeeperTransporter = zookeeperTransporter;
}
@Override
protected DynamicConfiguration createDynamicConfiguration(URL url) {
return new ZookeeperDynamicConfiguration(url, zookeeperTransporter);
}
}
自适应扩展点
@Adaptive
两种实现方式:、
类的实现方式
提前写好了一个自适应的扩展点->主要目的就是针对具体的实现进行适配
org.apache.dubbo.common.extension.ExtensionLoader
private ExtensionLoader(Class<?> type) {
this.type = type;
objectFactory = (type == ExtensionFactory.class ? null : ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension());
}
方法的实现方式
org.apache.dubbo.rpc.Protocol
@Adaptive
<T> Exporter<T> export(Invoker<T> invoker) throws RpcException;
激活扩展点
@Activate(group = {CONSUMER, PROVIDER}, value = CACHE_KEY)
org/apache/dubbo/common/extension/ExtensionLoader
/**
* Get activate extensions.
*
* @param url url
* @param values extension point names
* @param group group
* @return extension list which are activated
* @see org.apache.dubbo.common.extension.Activate
*/
public List<T> getActivateExtension(URL url, String[] values, String group) {
List<T> exts = new ArrayList<>();
List<String> names = values == null ? new ArrayList<>(0) : Arrays.asList(values);
if (!names.contains(REMOVE_VALUE_PREFIX + DEFAULT_KEY)) {
getExtensionClasses();
for (Map.Entry<String, Object> entry : cachedActivates.entrySet()) {
String name = entry.getKey();
Object activate = entry.getValue();
String[] activateGroup, activateValue;
if (activate instanceof Activate) {
activateGroup = ((Activate) activate).group();
activateValue = ((Activate) activate).value();
} else if (activate instanceof com.alibaba.dubbo.common.extension.Activate) {
activateGroup = ((com.alibaba.dubbo.common.extension.Activate) activate).group();
activateValue = ((com.alibaba.dubbo.common.extension.Activate) activate).value();
} else {
continue;
}
if (isMatchGroup(group, activateGroup)
&& !names.contains(name)
&& !names.contains(REMOVE_VALUE_PREFIX + name)
&& isActive(activateValue, url)) {
exts.add(getExtension(name));
}
}
exts.sort(ActivateComparator.COMPARATOR);
}
List<T> usrs = new ArrayList<>();
for (int i = 0; i < names.size(); i++) {
String name = names.get(i);
if (!name.startsWith(REMOVE_VALUE_PREFIX)
&& !names.contains(REMOVE_VALUE_PREFIX + name)) {
if (DEFAULT_KEY.equals(name)) {
if (!usrs.isEmpty()) {
exts.addAll(0, usrs);
usrs.clear();
}
} else {
usrs.add(getExtension(name));
}
}
}
if (!usrs.isEmpty()) {
exts.addAll(usrs);
}
return exts;
}