美文网首页
Dubbo SPI 机制

Dubbo SPI 机制

作者: 爱健身的兔子 | 来源:发表于2021-01-14 14:05 被阅读0次

    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博客

    相关文章

      网友评论

          本文标题:Dubbo SPI 机制

          本文链接:https://www.haomeiwen.com/subject/gqqeaktx.html