dubbo源码梳理之ExtensionLoader
Posted double6
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了dubbo源码梳理之ExtensionLoader相关的知识,希望对你有一定的参考价值。
ExtensionLoader是像SPI(Service Provider Interface)一样进行扩展加载的工具。在dubbo中,需要扩展的接口使用@SPI注解标注。在java的SPI方式中,只需要将实现类一行一行的写在META-INF/services/的配置文件中即可。但是ExtensionLoader需要的配置文件是K-V样式的。如dubbo-rpc-dubbo下的META-INF/dubbo/internal/org.apache.dubbo.rpc.Protocol配置文件:
dubbo=org.apache.dubbo.rpc.protocol.dubbo.DubboProtocol
dubbo给出的原因解释是:如果这种扩展类不存在的话,因不能定位到扩展的id而不能对应上该扩展类的异常信息。也就是说,给这个扩展类一个具体的名字,方便定位异常原因。
一、ExtensionLoader
每个扩展组件一个 ExtensionLoader。
ExtensionLoader中存放着原始的class(private final Class<?> type) 和对应的objectFactory(private final ExtensionFactory objectFactory;)。
ExtensionLoader主要提供两个功能API:
获得扩展实例
ExtensionLoader.getExtensionLoader(Protocol.class).getExtension("dubbo");
获得自适应扩展实例
ExtensionLoader.getExtensionLoader(Protocol.class).getAdaptiveExtension();
ExtensionFactory用于对扩展实例的字段进行注入。比如扩展实例依赖其他实例对象,这些被依赖的实例对象,可以被ExtensionFactory实例化出来并注入到该扩展实例的相应字段上。
还需要说明的是,ExtensionLoader中有两个核心的字段是静态类型的,也就是全局的,也就是说某个接口类只有一个ExtentionLoader,一个扩展实现类只有一个实例化对象,也就是说是单例的:
// 接口类对应的ExtentionLoader
private static final ConcurrentMap<Class<?>, ExtensionLoader<?>> EXTENSION_LOADERS = new ConcurrentHashMap<>(64);
// 扩展实现类对应的实例化对象
private static final ConcurrentMap<Class<?>, Object> EXTENSION_INSTANCES = new ConcurrentHashMap<>(64);
FrameworkExt.class是一个基础的扩展类:包括config、environment、repository。
但是ExtensionFactory.class的ExtensionLoader中不存在对应的objectFactory。
ApplicationModel
是一个dubbo应用的抽象,包括服务端和客户端信息。
二、如何从配置文件中加载类
dubbo给了3种策略,可以从三个位置加载配置文件。
DubboInternalLoadingStrategy META-INF/dubbo/internal/ 不可覆盖 优先级最高
DubboLoadingStrategy META-INF/dubbo/ 可覆盖 优先级中等
ServicesLoadingStrategy META-INF/services/ 可覆盖 优先级最低
优先级决定了load时的遍历顺序,先使用优先级最高的策略加载,再使用优先级低的加载。但是后面两个都是可以覆盖的。例如:META-INF/dubbo/internal/和META-INF/dubbo/都有配置某个类,则会使用META-INF/dubbo/中配置的类。也就是业务配置可以覆盖dubbo内部的配置。
注意:一个配置文件中只能有一个@Adaptive注解的类。
三、Adaptive
Protocol是一种@Adaptive类。
Adaptive类会自动生成一段代码。以Protocol为例会自动生成如下代码:
package org.apache.dubbo.rpc;
import org.apache.dubbo.common.extension.ExtensionLoader;
public class Protocol$Adaptive implements org.apache.dubbo.rpc.Protocol {
public void destroy() {
throw new UnsupportedOperationException("The method public abstract void org.apache.dubbo.rpc.Protocol.destroy() " +
"of interface org.apache.dubbo.rpc.Protocol is not adaptive method!");
}
public int getDefaultPort() {
throw new UnsupportedOperationException("The method public abstract int org.apache.dubbo.rpc.Protocol.getDefaultPort() " +
"of interface org.apache.dubbo.rpc.Protocol is not adaptive method!");
}
public org.apache.dubbo.rpc.Exporter export(org.apache.dubbo.rpc.Invoker arg0) throws org.apache.dubbo.rpc.RpcException {
if (arg0 == null) throw new IllegalArgumentException("org.apache.dubbo.rpc.Invoker argument == null");
if (arg0.getUrl() == null) throw new IllegalArgumentException("org.apache.dubbo.rpc.Invoker argument getUrl() == null");
org.apache.dubbo.common.URL url = arg0.getUrl();
String extName = ( url.getProtocol() == null ? "dubbo" : url.getProtocol() );
if(extName == null) throw new IllegalStateException("Failed to get extension (org.apache.dubbo.rpc.Protocol) name from url (" + url.toString() + ") use keys([protocol])");
org.apache.dubbo.rpc.Protocol extension = (org.apache.dubbo.rpc.Protocol)ExtensionLoader.getExtensionLoader(org.apache.dubbo.rpc.Protocol.class).getExtension(extName);
return extension.export(arg0);
}
public org.apache.dubbo.rpc.Invoker refer(java.lang.Class arg0, org.apache.dubbo.common.URL arg1) throws org.apache.dubbo.rpc.RpcException {
if (arg1 == null) throw new IllegalArgumentException("url == null");
org.apache.dubbo.common.URL url = arg1;
String extName = ( url.getProtocol() == null ? "dubbo" : url.getProtocol() );
if(extName == null) throw new IllegalStateException("Failed to get extension (org.apache.dubbo.rpc.Protocol) name from url (" + url.toString() + ") use keys([protocol])");
org.apache.dubbo.rpc.Protocol extension = (org.apache.dubbo.rpc.Protocol)ExtensionLoader.getExtensionLoader(org.apache.dubbo.rpc.Protocol.class).getExtension(extName);
return extension.refer(arg0, arg1);
}
public java.util.List getServers() {
throw new UnsupportedOperationException("The method public default java.util.List org.apache.dubbo.rpc.Protocol.getServers() of interface org.apache.dubbo.rpc.Protocol is not adaptive method!");
}
}
猜测Adaptive主要干的事:
以上是关于dubbo源码梳理之ExtensionLoader的主要内容,如果未能解决你的问题,请参考以下文章