Dubbo SPI 机制

1 概述

Dubbo 采用了 SPI 的思想,不过没有用 JDK 的 SPI 机制,是自己实现的一套 SPI 机制。在 Dubbo 的源码中,很多地方会存在下面这样的三种代码,分别是自适应扩展点、指定名称的扩展点、激活扩展点。

ExtensionLoader.getExtensionLoader(xxx.class).getAdaptiveExtension();
ExtensionLoader.getExtensionLoader(xxx.class).getExtension(name);
ExtensionLoader.getExtensionLoader(xxx.class).getActivateExtension(url, key);

在dubbo里面对很多组件,都是保留一个接口和多个实现,然后在系统运行的时候动态的根据配置去找到对应的实现类。

2 Java SPI 的不足

Java SPI 的实现机制本身存在下面的不足:

  • 不能按需加载。Java SPI 在加载扩展点的时候,会一次性加载所有可用的扩展点,很多是不需要的,会浪费系统资源。
  • 获取某个实现类的方式不够灵活,只能通过 Iterator 形式获取,不能根据某个参数来获取对应的实现类。
  • 不支持 AOP 与依赖注入。
  • 如果扩展点加载失败,会导致调用方报错,而且这个错误很难定位到是这个原因。

3 Dubbo SPI 机制

Dubbo 的 SPI 实现原理和 Java SPI 相似,只不过增强了一些功能和优化。Java SPI 的是把所有的spi都加载到内存,但对于 Dubbo 来说可能只需要加载用户指定的实现方式,而不需要全部加载进来,全部加载也会有性能问题,所以 Dubbo 实现的是在有用到的时候去加载这些扩展组件。

SPI机制的注解:

  1. @SPI注解,被此注解标记的接口,就表示是一个可扩展的接口,并标注默认值。

  2. @Adaptive注解,有两种注解方式:一种是注解在类上,一种是注解在方法上。

  3. @Activate注解,此注解需要注解在类上或者方法上,并注明被激活的条件,以及所有的被激活实现类中的排序信息。

4 SPI实战

这里以 Dubbo 中protocol接口的扩展作为实战。

4.1 定义接口的扩展

通过@SPI接口标注一个接口即可被 Dubbo 的 SPI 机制加载。@SPI注解的value值表示此接口默认加载的实现类的名称(在配置文件中定义)。

@SPI("dubbo")  
public interface Protocol {  

    int getDefaultPort();  

    @Adaptive  
    <T> Exporter<T> export(Invoker<T> invoker) throws RpcException;  

    @Adaptive  
    <T> Invoker<T> refer(Class<T> type, URL url) throws RpcException;  

    void destroy();  

} 
4.2 配置资源文件

在dubbo的jar中META-INF/dubbo/internal/目录下面以接口的全限定名称编写配置文件,配置文件以键值对的形式存在。左面是简称,右边是接口的具体实现类的全限定名称。如下是org.apache.dubbo.rpc.Protocol的资源配置文件。

filter=org.apache.dubbo.rpc.protocol.ProtocolFilterWrapper
listener=org.apache.dubbo.rpc.protocol.ProtocolListenerWrapper
mock=org.apache.dubbo.rpc.support.MockProtocol
dubbo=org.apache.dubbo.rpc.protocol.dubbo.DubboProtocol
injvm=org.apache.dubbo.rpc.protocol.injvm.InjvmProtocol
rmi=org.apache.dubbo.rpc.protocol.rmi.RmiProtocol
hessian=org.apache.dubbo.rpc.protocol.hessian.HessianProtocol
http=org.apache.dubbo.rpc.protocol.http.HttpProtocol

org.apache.dubbo.rpc.protocol.webservice.WebServiceProtocol
thrift=org.apache.dubbo.rpc.protocol.thrift.ThriftProtocol
native-thrift=org.apache.dubbo.rpc.protocol.nativethrift.ThriftProtocol
memcached=org.apache.dubbo.rpc.protocol.memcached.MemcachedProtocol
redis=org.apache.dubbo.rpc.protocol.redis.RedisProtocol
rest=org.apache.dubbo.rpc.protocol.rest.RestProtocol
xmlrpc=org.apache.dubbo.xml.rpc.protocol.xmlrpc.XmlRpcProtocol
registry=org.apache.dubbo.registry.integration.RegistryProtocol
qos=org.apache.dubbo.qos.protocol.QosProtocolWrapper
4.3 获取默认接口实现类

通过下面的代码就可以获取protocol的默认实现类:

Protocol protocol = ExtensionLoader.getExtensionLoader(Protocol.class).getDefaultExtension();

如果想要动态替换掉默认的实现类,需要使用 @Adaptive 注解,Protocol 接口中,有两个方法加了 @Adaptive 注解,就是说那俩接口会被代理实现。

Protocol protocol = ExtensionLoader.getExtensionLoader(Protocol.class).getAdaptiveExtension();

上面的方法会在运行的时候会针对 Protocol 生成代理类,这个代理类的那俩方法里面会有代理代码,代理代码会在运行的时候动态根据 url 中的 protocol 来获取那个 key,默认是 "dubbo",如果指定了别的 key,那么就会获取别的实现类的实例了。

5 ExtensionLoader源码解析

5.1 ExtensionLoader成员属性
public class ExtensionLoader<T> {

    // 常量存储 {class-ExtensionLoader} 对
    private static final ConcurrentMap<Class<?>, ExtensionLoader<?>> EXTENSION_LOADERS = new ConcurrentHashMap<>(64);

    // 常量存储 {实现类class对象 ~ 实现类实例} 对
    private static final ConcurrentMap<Class<?>, Object> EXTENSION_INSTANCES = new ConcurrentHashMap<>(64);

    // 接口class
    private final Class<?> type;

    // 对象工厂,不同接口对应 ExtensionLoader 的对象工厂属性是相同的
    private final ExtensionFactory objectFactory;

    /****以下属性是对象实例不同维度的缓存*****/ 
    private final ConcurrentMap<Class<?>, String> cachedNames = new ConcurrentHashMap<>();

    private final Holder<Map<String, Class<?>>> cachedClasses = new Holder<>();

    private final Map<String, Object> cachedActivates = new ConcurrentHashMap<>();
    private final ConcurrentMap<String, Holder<Object>> cachedInstances = new ConcurrentHashMap<>();
    private final Holder<Object> cachedAdaptiveInstance = new Holder<>();
    private volatile Class<?> cachedAdaptiveClass = null;
    private String cachedDefaultName;
    private volatile Throwable createAdaptiveInstanceError;

    private Set<Class<?>> cachedWrapperClasses;

    private Map<String, IllegalStateException> exceptions = new ConcurrentHashMap<>();

    // 接口对应实现类名称存储路径,通过Java SPI加载LoadingStrategy的实现类。
    private static volatile LoadingStrategy[] strategies = loadLoadingStrategies();
    ...
}

说明:

  • 每个接口Class会创建对应的ExtensionLoader对象,并存储到 EXTENSION_LOADERS 中。

  • 每个接口的多个实现类Class创建的对应实例,存储到EXTENSION_INSTANCES;通常对应接口实现类对象是单例的。

5.1 ExtensionLoader的创建

通过ExtensionLoader.getExtensionLoader()方法创建ExtensionLoader的实例,在实例化ExtensionLoader的时候会创建一个AdaptiveExtensionFactory。

public class ExtensionLoader<T> {
   private ExtensionLoader(Class<?> type) {
        this.type = type;
        // 创建objectFactory的【Adaptive:自适应】实例 或 不创建
        objectFactory = (type == ExtensionFactory.class ? null : ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension());
    }

    private static <T> boolean withExtensionAnnotation(Class<T> type) {
        return type.isAnnotationPresent(SPI.class);
    }

    // 通过接口Class get 对应ExtensionLoader<?> 对象
    // ExtensionLoader 中最常用的方法;通常第一步先获取到接口class对应的ExtensionLoader对象
    @SuppressWarnings("unchecked")
    public static <T> ExtensionLoader<T> getExtensionLoader(Class<T> type) {
        if (type == null) {
            throw new IllegalArgumentException("Extension type == null");
        }
        if (!type.isInterface()) {
            throw new IllegalArgumentException("Extension type (" + type + ") is not an interface!");
        }
        // 接口必须有@SPI注解, dubbo框架的规定
        // 如需要通过dubbo SPI 方式加载实现类需要遵守该规定
        // SPI 方式加载,下文有解释
        if (!withExtensionAnnotation(type)) {
            throw new IllegalArgumentException("Extension type (" + type +
                    ") is not an extension, because it is NOT annotated with @" + SPI.class.getSimpleName() + "!");
        }
        // 从存储常量map中获取 
        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;
    }
}
5.2 ExtensionFactory

ExtensionFactory主要用于ExtensionLoader中的依赖注入。下面是他的三个实现类:

  1. SpringExtensionFactory:实现spring容器中bean的依赖注入。

  2. AdaptiveExtensionFactory:默认的自适应代理类。

  3. SpiExtensionFactory:实现在SPI接口中的依赖注入。

ExtensionFactory具有以下特性:

  • 每个ExtensionLoader<?>对象持有的ExtensionFactory属性是AdaptiveExtensionFactory;除了ExtensionLoader<extensionfactory>。

  • ExtensionLoader <extensionfactory>持有的ExtensionFactory属性是null。

  • AdaptiveExtensionFactory类对象在整个应用运行中只有一个。

下面是AdaptiveExtensionFactory的源码:

// 该类有@Adaptive
// 对应ExtensionLoader<ExtensionFactory> 中 
// cachedAdaptiveInstance,cachedAdaptiveClass,createAdaptiveInstanceError 
// 属性都与AdaptiveExtensionFactory相关
@Adaptive
public class AdaptiveExtensionFactory implements ExtensionFactory {

    // 所有ExtensionFactory实现类实例对象【排查AdaptiveExtensionFactory】
    // ExtensionLoader<ExtensionFactory>实例中cachedAdaptiveInstance属性是 AdaptiveExtensionFactory对象实例
    private final List<ExtensionFactory> factories;

    public AdaptiveExtensionFactory() {

        ExtensionLoader<ExtensionFactory> loader = ExtensionLoader.getExtensionLoader(ExtensionFactory.class);
        List<ExtensionFactory> list = new ArrayList<ExtensionFactory>();
        // 加载所有ExtensionFactory实现类【此处不包含AdaptiveExtensionFactory 本身】
        for (String name : loader.getSupportedExtensions()) {
            // 循环存储每个实现类实例到list
            list.add(loader.getExtension(name));
        }
        factories = Collections.unmodifiableList(list);
    }

    @Override
    public <T> T getExtension(Class<T> type, String name) {
        // AdaptiveExtensionFactory#getExtension 方法则会循环从每个工厂中获取对象【取到为止】
        for (ExtensionFactory factory : factories) {
            T extension = factory.getExtension(type, name);
            if (extension != null) {
                return extension;
            }
        }
        return null;
    }

}

// dubbo定义的SPI工厂
// SPI工厂存储
public class SpiExtensionFactory implements ExtensionFactory {

    @Override
    public <T> T getExtension(Class<T> type, String name) {
        if (type.isInterface() && type.isAnnotationPresent(SPI.class)) {
            ExtensionLoader<T> loader = ExtensionLoader.getExtensionLoader(type);
            if (!loader.getSupportedExtensions().isEmpty()) {
                // 返回对应接口的自适应实例
                // 该方法调用时会设置cachedAdaptiveInstance,cachedAdaptiveClass,createAdaptiveInstanceError 
                return loader.getAdaptiveExtension();
            }
        }
        return null;
    }
}

public class SpringExtensionFactory implements ExtensionFactory {

   // Spring 对象工厂
    private static final Set<ApplicationContext> CONTEXTS = new ConcurrentHashSet<ApplicationContext>();

    public <T> T getExtension(Class<T> type, String name) {

        //SPI should be get from SpiExtensionFactory
        if (type.isInterface() && type.isAnnotationPresent(SPI.class)) {
            return null;
        }

        // bena 工厂获取对象
        for (ApplicationContext context : CONTEXTS) {
            T bean = BeanFactoryUtils.getOptionalBean(context, name, type);
            if (bean != null) {
                return bean;
            }
        }

        return null;
    }
    ...
}

流程说明:

  1. AdaptiveExtensionFactory在实例化的时候,通过SPI方式加载SpiExtensionFactory,SpringExtensionFactory实例,并存储到factories 列表中。

  2. getExtension方法会遍历调用对应实现类的getExtension方法获取bean对象。

    • SpiExtensionFactory 中getExtension 会从对应ExtensionLoader<?>中获取adaptive 对象实例。

    • SpringExtensionFactory 中getExtension 会从ApplicationContext中获取bean 对象实例。

5.3 getExtension方法获取实例
    public T getExtension(String name, boolean wrap) {
        if (StringUtils.isEmpty(name)) {
            throw new IllegalArgumentException("Extension name == null");
        }
        if ("true".equals(name)) {
            return getDefaultExtension();
        }
        //创建Holder
        final Holder<Object> holder = getOrCreateHolder(name);
        Object instance = holder.get();
        if (instance == null) {
            synchronized (holder) {
                instance = holder.get();
                if (instance == null) {
                    //创建扩展点实例
                    instance = createExtension(name, wrap);
                    holder.set(instance);
                }
            }
        }
        return (T) instance;
    }
    private T createExtension(String name, boolean wrap) {
        //获取扩展点的Class对象。
        Class<?> clazz = getExtensionClasses().get(name);
        if (clazz == null) {
            throw findException(name);
        }
        try {
            //根据Class对象重缓存中获取实例。
            T instance = (T) EXTENSION_INSTANCES.get(clazz);
            if (instance == null) {
                //实例化对象并放入缓存。
                EXTENSION_INSTANCES.putIfAbsent(clazz, clazz.newInstance());
                instance = (T) EXTENSION_INSTANCES.get(clazz);
            }
            //依赖注入
            injectExtension(instance);

            if (wrap) {
                //包装对象
                List<Class<?>> wrapperClassesList = new ArrayList<>();
                if (cachedWrapperClasses != null) {
                    wrapperClassesList.addAll(cachedWrapperClasses);
                    wrapperClassesList.sort(WrapperComparator.COMPARATOR);
                    Collections.reverse(wrapperClassesList);
                }

                if (CollectionUtils.isNotEmpty(wrapperClassesList)) {
                    for (Class<?> wrapperClass : wrapperClassesList) {
                        Wrapper wrapper = wrapperClass.getAnnotation(Wrapper.class);
                        if (wrapper == null
                                || (ArrayUtils.contains(wrapper.matches(), name) && !ArrayUtils.contains(wrapper.mismatches(), name))) {
                            instance = injectExtension((T) wrapperClass.getConstructor(type).newInstance(instance));
                        }
                    }
                }
            }
            //初始化对象
            initExtension(instance);
            return instance;
        } catch (Throwable t) {
            throw new IllegalStateException("Extension instance (name: " + name + ", class: " +
                    type + ") couldn't be instantiated: " + t.getMessage(), t);
        }
    }

流程说明:

  1. 先从缓存中获取对象,没有就去创建。

  2. 从缓存中获取Class对象,没有就去创建。

  3. 实例化对象并放入缓存中。

  4. 对象依赖注入。

  5. 包装对象。

  6. 初始化对象。

5.4 getExtensionClasses方法
    // ExtensionLoader中所有get***Extension(...)方法在缓存没有命中时,都会调用该方法
   // 加载接口class所有的实现类
    private Map<String, Class<?>> getExtensionClasses() {
        Map<String, Class<?>> classes = cachedClasses.get();
        if (classes == null) {
            synchronized (cachedClasses) {
                classes = cachedClasses.get();
                if (classes == null) {
                    // 第一次调用时load 实现类class
                    classes = loadExtensionClasses();
                    cachedClasses.set(classes);
                }
            }
        }
        return classes;
    }

    // 加载实现类class
    private Map<String, Class<?>> loadExtensionClasses() {
        // @SPI("defaultName") 接口中的value值则为defaultName
        cacheDefaultExtensionName();

        Map<String, Class<?>> extensionClasses = new HashMap<>();
        // META-INF/dubbo/external/,META-INF/dubbo/external/,META-INF/dubbo/
        for (LoadingStrategy strategy : strategies) {
            // 加载所有jar包 下面对应的文件
            loadDirectory(extensionClasses, strategy.directory(), type.getName(), strategy.preferExtensionClassLoader(), strategy.overridden(), strategy.excludedPackages());
            loadDirectory(extensionClasses, strategy.directory(), type.getName().replace("org.apache", "com.alibaba"), strategy.preferExtensionClassLoader(), strategy.overridden(), strategy.excludedPackages());
        }

        return extensionClasses;
    }
5.5 扩展点的依赖注入
public class ExtensionLoader<T> {
    private T injectExtension(T instance) {

        if (objectFactory == null) {
            return instance;
        }

        try {
            for (Method method : instance.getClass().getMethods()) {
                // 非set方法则不处理
                if (!isSetter(method)) {
                    continue;
                }

                 // 有@DisableInject的方法不处理
                if (method.getAnnotation(DisableInject.class) != null) {
                    continue;
                }
                Class<?> pt = method.getParameterTypes()[0];
                // 基础类型等属性不处理 int, date, string
                if (ReflectUtils.isPrimitives(pt)) {
                    continue;
                }

                try {
                    // 截取 setXXX 方法名中的XXX字符串
                    String property = getSetterProperty(method);
                    // AdaptiveExtensionFactory 对象工厂中获取对象
                    Object object = objectFactory.getExtension(pt, property);
                    if (object != null) {
                       // 属性注入
                        method.invoke(instance, object);
                    }
                } catch (Exception e) {
                    logger.error("Failed to inject via method " + method.getName()
                            + " of interface " + type.getName() + ": " + e.getMessage(), e);
                }

            }
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
        }
        return instance;
    }

}

注意:

  • dubbo 采用setXXX的方式进行属性注入。
  • 属性对象实例通过AdaptiveExtensionFactory 对象工厂getExtension方法获取。
  • 如果属性对象只在SpiExtensionFactory对象工厂中通常返回对应属性的adaptive实例。
5.6 扩展点的包装器

public class ExtensionLoader<T> {

    // 判断是否是包装类
    private boolean isWrapperClass(Class<?> clazz) {
        try {
            clazz.getConstructor(type);
            return true;
        } catch (NoSuchMethodException e) {
            return false;
        }
    }

    private void cacheWrapperClass(Class<?> clazz) {
        if (cachedWrapperClasses == null) {
            cachedWrapperClasses = new ConcurrentHashSet<>();
        }
        // 包装类集合
        cachedWrapperClasses.add(clazz);
    }

    // SPI加载接口class对应的实现类
    private void loadClass(Map<String, Class<?>> extensionClasses, java.net.URL resourceURL, Class<?> clazz, String name,
                           boolean overridden) throws NoSuchMethodException {
        if (!type.isAssignableFrom(clazz)) {
            throw new IllegalStateException("Error occurred when loading extension class (interface: " +
                    type + ", class line: " + clazz.getName() + "), class "
                    + clazz.getName() + " is not subtype of interface.");
        }
        if (clazz.isAnnotationPresent(Adaptive.class)) {
            cacheAdaptiveClass(clazz, overridden);
        } else if (isWrapperClass(clazz)) {
            // add到包装类集合
            // ExtensionLoader<?>对象实例 cachedNames,cachedClasses属性没有包装类
            // getExtensionLoader(Protocol.class).getExtension("filter") 调用会报错,因为cachedClasses没有对应记录
            // 【在dubbo-rpc-api】jar 中的META-INF/dubbo/internal/org.apache.dubbo.rpc.Protocol
            // filter=org.apache.dubbo.rpc.protocol.ProtocolFilterWrapper
            // listener=org.apache.dubbo.rpc.protocol.ProtocolListenerWrapper
            // mock=org.apache.dubbo.rpc.support.MockProtocol
            cacheWrapperClass(clazz);
        } else {
            clazz.getConstructor();
            if (StringUtils.isEmpty(name)) {
                name = findAnnotationName(clazz);
                if (name.length() == 0) {
                    throw new IllegalStateException("No such extension name for the class " + clazz.getName() + " in the config " + resourceURL);
                }
            }

            String[] names = NAME_SEPARATOR.split(name);
            if (ArrayUtils.isNotEmpty(names)) {
                cacheActivateClass(clazz, names[0]);
                for (String n : names) {
                    cacheName(clazz, n);
                    saveInExtensionClass(extensionClasses, clazz, n, overridden);
                }
            }
        }
    }
}

SPI通过LoadingStrategy加载Class时,会判断当前Class是否有对应Type的构造方法,如果有,表示是包装器就放入Wrapper的缓存中,在创建对象时包装对象。

5.7 扩展点初始化
private void initExtension(T instance) {
        if (instance instanceof Lifecycle) {
            Lifecycle lifecycle = (Lifecycle) instance;
            lifecycle.initialize();
        }
    }

如果对象实现了Lifecycle接口,就进行初始化。

6 Adaptive extension(自适应扩展点)

// 获取接口对应adaptive对象实例
    public T getAdaptiveExtension() {
        Object instance = cachedAdaptiveInstance.get();
        if (instance == null) {
            if (createAdaptiveInstanceError != null) {
                throw new IllegalStateException("Failed to create adaptive instance: " +
                        createAdaptiveInstanceError.toString(),
                        createAdaptiveInstanceError);
            }

            synchronized (cachedAdaptiveInstance) {
                instance = cachedAdaptiveInstance.get();
                if (instance == null) {
                    try {
                        // 第一次调用时进行创建
                        instance = createAdaptiveExtension();
                        cachedAdaptiveInstance.set(instance);
                    } catch (Throwable t) {
                        createAdaptiveInstanceError = t;
                        throw new IllegalStateException("Failed to create adaptive instance: " + t.toString(), t);
                    }
                }
            }
        }

        return (T) instance;
    }

    // 创建接口对应adaptive对象实例
    private T createAdaptiveExtension() {
        try {
           // injectExtension :实例对象属性注入(dubbo实现的 IOC)
           // getAdaptiveExtensionClass:获取自适应的Class<?>对象
           // 没有显示定义则使用AdaptiveClassCodeGenerator生成java代码编译成class文件,并加载成Class<?> 对象
           // newInstance:反射生成对象
            return injectExtension((T) getAdaptiveExtensionClass().newInstance());
        } catch (Exception e) {
            throw new IllegalStateException("Can't create adaptive extension " + type + ", cause: " + e.getMessage(), e);
        }
    }

    private Class<?> getAdaptiveExtensionClass() {
        getExtensionClasses();
        if (cachedAdaptiveClass != null) {
            // 有显示定义 或 已加载AdaptiveClass【.class】到内存
            return cachedAdaptiveClass;
        }
        // 创建AdaptiveClass
        return cachedAdaptiveClass = createAdaptiveExtensionClass();
    }

    private Class<?> createAdaptiveExtensionClass() {
        // 代码字符串
        // 生成代码的方法很复杂,但功能相对明确
        String code = new AdaptiveClassCodeGenerator(type, cachedDefaultName).generate();
        ClassLoader classLoader = findClassLoader();
        org.apache.dubbo.common.compiler.Compiler compiler = ExtensionLoader.getExtensionLoader(org.apache.dubbo.common.compiler.Compiler.class).getAdaptiveExtension();
        // 编译并加载成Class<?>对象
        return compiler.compile(code, classLoader);
    }

流程说明:

  1. 先尝试从缓存中获取,获取不到就创建。

  2. 生成代理对象的代码。

  3. 编译生成代理对象。

注意:

  • @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 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;
        // “dubbo”字符串与 Protocol上 @SPI(“dubbo”)注解value对应,即默认值
        // url.get***() 与Protocol#refer上@Adaptive 注解对应
        // 如果@Adaptive 没有value则 与接口simpleName对应
        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])");
        // 根据extname 获取对应的实例对象【策略模式】
        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 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);
    }

    // 没有@Adaptive注解的其余方法不提供调用
    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!");
    }

    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!");
    }
}

7 activate extension(自动激活扩展点)

@Activate 提供了一些配置来允许我们配置加载条件,比如 group 过滤,比如 key 过滤。

如下展示了ProtocolWrapper如何通过@Activate注解包装Filter链的过程。

//在ExtensionLoader#loadExtensionClasses装载资源Class的时候放入缓存。
private void cacheActivateClass(Class<?> clazz, String name) {
        // @Activate 注解判断
        Activate activate = clazz.getAnnotation(Activate.class);
        if (activate != null) {
            // put 到 cachedActivates 属性
            cachedActivates.put(name, activate);
        } else {
            com.alibaba.dubbo.common.extension.Activate oldActivate = clazz.getAnnotation(com.alibaba.dubbo.common.extension.Activate.class);
            if (oldActivate != null) {
                cachedActivates.put(name, oldActivate);
            }
        }
    }

// 激活注解
@Activate(group = PROVIDER, value = ACCESS_LOG_KEY)
public class AccessLogFilter implements Filter {。。。}

@Activate(group = CONSUMER, value = ACTIVES_KEY)
public class ActiveLimitFilter implements Filter, Filter.Listener {。。。}

@Activate(order = 100)
public class ProtocolFilterWrapper implements Protocol {

    private static <T> Invoker<T> buildInvokerChain(final Invoker<T> invoker, String key, String group) {
        Invoker<T> last = invoker;
        // 获取被激活的filter对象
        List<Filter> filters = ExtensionLoader.getExtensionLoader(Filter.class).getActivateExtension(invoker.getUrl(), key, group);

        return last;
    }

    @Override
    public <T> Exporter<T> export(Invoker<T> invoker) throws RpcException {
        if (UrlUtils.isRegistry(invoker.getUrl())) {
            return protocol.export(invoker);
        }
        // 创建invoker 对象并暴露
        return protocol.export(buildInvokerChain(invoker, SERVICE_FILTER_KEY, CommonConstants.PROVIDER));
    }

    @Override
    public <T> Invoker<T> refer(Class<T> type, URL url) throws RpcException {
        if (UrlUtils.isRegistry(url)) {
            return protocol.refer(type, url);
        }
        // 创建invoker 对象并返回
        return buildInvokerChain(protocol.refer(type, url), REFERENCE_FILTER_KEY, CommonConstants.CONSUMER);
    }

dubbo ExtensionLoader源码分析_俗民·不自扰-CSDN博客

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,456评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,370评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,337评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,583评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,596评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,572评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,936评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,595评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,850评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,601评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,685评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,371评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,951评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,934评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,167评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,636评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,411评论 2 342

推荐阅读更多精彩内容