dubbo基于SPI思想的内核实现

dubbo基于SPI思想的内核实现

SPI机制

SPI 全称为 Service Provider Interface,是一种服务发现机制。SPI 的本质是将接口实现类的全限定名配置在文件中,并由服务加载器读取配置文件,加载实现类。这样可以在运行时,动态为接口加载实现类。正因此特性,我们可以很容易的通过 SPI 机制为我们的程序提供拓展功能,比如数据库访问、日志等都是采用这种形式。一般通用组件为了提升扩展性,基于接口编程,将操作接口形成标准规范,开放多种扩展实现,是组件具有可插拔性,也符合开闭设计原则。
dubbo 的扩展实现很多,比如协议拓展、调用拦截扩展、引用监听拦截拓展等

JDK SPI 机制介绍

举个例子演示下JDK 的SPI
定义一个interface:

package com.momo.jdk.spi;

public interface SPI {
    SPI getExtension();
}

实现类:

package com.momo.jdk.spi;

public class HelloSPI implements SPI {
    @Override
    public SPI getExtension() {
        System.out.println("这是 HelloSPI ~~~~~~~");
        return new HelloSPI();
    }
}
package com.momo.jdk.spi;

public class Hello2SPI implements SPI {
    @Override
    public SPI getExtension() {
        System.out.println("这是 Hello2SPI Hello2SPI Hello2SPI");
        return new Hello2SPI();
    }
}

ServiceLoader会遍历所有jar查找META-INF/services/ 下定义的类并加载
在META-INF/services 定一个名为接口SPI 的全限定名:com.momo.jdk.spo.SPI 的文件:
[外链图片转存失败(img-OR3eNnHO-1564366186540)(media/15497013856273/15497145191481.jpg)]
内容为:

com.momo.jdk.spi.HelloSPI
com.momo.jdk.spi.Hello2SPI

测试方法:

public class SPITest {
    public static void main(String[] args) {
        ServiceLoader<SPI> serviceLoader = ServiceLoader.load(SPI.class);
        System.out.println("Java SPI");
        serviceLoader.forEach(SPI::getExtension);
    }
}

运行结果:
[外链图片转存失败(img-vUirpICt-1564366186542)(media/15497013856273/15497146175001.jpg)]
从结果来看,这两个实现类都被加载并且输出了相应内容。接下来看看dubbo的SPI

dubbo SPI 示例

Dubbo 的扩展点加载从 JDK 标准的 SPI (Service Provider Interface) 扩展点发现机制加强而来。

下面我们通过扩展dubbo得filter来看下dubbo的SPI
实现filter:

public class MyTestFilter implements Filter {
    private TestSPIDemoService testSPIDemoService;
    @Override
    public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
        Result result = invoker.invoke(invocation);
        System.out.println(testSPIDemoService.getTestSPIResult());
        return result;
    }

    public void setTestSPIDemoService(TestSPIDemoService testSPIDemoService) {
        this.testSPIDemoService = testSPIDemoService;
    }
}

约定:
在扩展类的 jar 包内,放置扩展点配置文件 META-INF/dubbo/接口全限定名,内容为:配置名=扩展实现类全限定名,多个实现类用换行符分隔。

META-INF/dubbo/:myTest=com.momo.sentinel.spi.MyTestFilter
[外链图片转存失败(img-wEtN29nX-1564366186542)(media/15497013856273/15497233065729.jpg)]
执行结果:
[外链图片转存失败(img-uJhucxrt-1564366186543)(media/15497013856273/15497272535005.jpg)]

在学习dubbo SPI 之前推荐先移步官网dubbo 扩展点加载了解下dubbo的四大特性:扩展点自动包装、扩展点自动装配、扩展点自适应、扩展点自动激活

ExtensionLoader

dubbo扩展机制实现的核心是ExtensionLoader,几乎所有的扩展实现都在这个类里面。每个可扩展接口扩展实现类和实现实例的管理都是通过ExtensionLoader进行,每个接口维护一个单例ExtensionLoader,所有可扩展的接口实现都维护在ExtensionLoader中
唯一获取ExtensionLoader对象的入口就是ExtensionLoader#getExtensionLoader(Class type)方法
主要流程图

    @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 interface!");
        }
        if (!withExtensionAnnotation(type)) {
            throw new IllegalArgumentException("Extension type (" + type +
                    ") is not extension, because WITHOUT @" + SPI.class.getSimpleName() + " Annotation!");
        }
        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;
    }

会校验尝试获取Loader的接口是否有@SPI注解,先在缓存中找,如果没有缓存,则调用私有构造方法:

  private ExtensionLoader(Class<?> type) {
        this.type = type;
        objectFactory = (type == ExtensionFactory.class ? null : ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension());
    }

这里有个重要对象:objectFactory。这个对象的作用就是自动装配依赖,也就是IOC,可以看出,除了ObjectFactory本身,所有扩展点都有ObjectFactory实例,这个也是通过SPI管理的,它是通过getAdaptiveExtension()方法获取的。

自适应扩展

友情提示:一个拓展接口,有且仅有一个 Adaptive 拓展实现类。

getAdaptiveExtension()

要构建自适应实例,先要有自适应的实现类,实现类有两种实现方式:一种是通过配置文件,一种是通过字节码方式动态生成。配置文件的自适应类通过在实现类上面加@Adaptive注解(例如:Compiler的AdaptiveCompiler实现),字节码生成的自适应类的在方法层面上加@Adaptive注解(例如:LoadBalance)。

  private Class<?> getAdaptiveExtensionClass() {
        //先通过配置文化加载实现类,并且识别自适应实现类
        getExtensionClasses();
        if (cachedAdaptiveClass != null) {
            return cachedAdaptiveClass;
        }
        //如果没有通过Adaptive注解标识的自适应实现类,则通过字节码创建
        return cachedAdaptiveClass = createAdaptiveExtensionClass();
    }

加载完配置文件后,检查缓存的自适应实现类,若没有,则通过字节码技术生成自适应类。调用createAdaptiveExtensionClass()方法,实际上是通过拼接class文本,然后通过compiler编译文本生成class。

通过配置文件加载自适应类

    private Map<String, Class<?>> loadExtensionClasses() {
        // 通过 @SPI 注解,获得默认的拓展实现类名
        final SPI defaultAnnotation = type.getAnnotation(SPI.class);
        if (defaultAnnotation != null) {
            String value = defaultAnnotation.value();
            if ((value = value.trim()).length() > 0) {
                String[] names = NAME_SEPARATOR.split(value);
                //有多个默认实现就抛异常
                if (names.length > 1) {
                    throw new IllegalStateException("more than 1 default extension name on extension " + type.getName()
                            + ": " + Arrays.toString(names));
                }
                if (names.length == 1) cachedDefaultName = names[0];
            }
        }
       // 从配置文件中,加载拓展实现类数组
        Map<String, Class<?>> extensionClasses = new HashMap<String, Class<?>>();
        loadDirectory(extensionClasses, DUBBO_INTERNAL_DIRECTORY);
        loadDirectory(extensionClasses, DUBBO_DIRECTORY);
        loadDirectory(extensionClasses, SERVICES_DIRECTORY);
        return extensionClasses;
    }
    
    private void loadDirectory(Map<String, Class<?>> extensionClasses, String dir) {
        // 完整的文件名
        String fileName = dir + type.getName();
        try {
            Enumeration<java.net.URL> urls;
            // 获得文件名对应的所有文件数组
            ClassLoader classLoader = findClassLoader();
            if (classLoader != null) {
                urls = classLoader.getResources(fileName);
            } else {
                urls = ClassLoader.getSystemResources(fileName);
            }
            // 遍历文件数组
            if (urls != null) {
                while (urls.hasMoreElements()) {
                    java.net.URL resourceURL = urls.nextElement();
                    loadResource(extensionClasses, classLoader, resourceURL);
                }
            }
        } catch (Throwable t) {
            logger.error("Exception when load extension class(interface: " +
                    type + ", description file: " + fileName + ").", t);
        }
    }
    
     private void loadResource(Map<String, Class<?>> extensionClasses, ClassLoader classLoader, java.net.URL resourceURL) {
        try {
            BufferedReader reader = new BufferedReader(new InputStreamReader(resourceURL.openStream(), "utf-8"));
            try {
                String line;
                while ((line = reader.readLine()) != null) {
                    // 跳过当前被注释掉的情况,例如 #spring=xxxxxxxxx
                    final int ci = line.indexOf('#');
                    if (ci >= 0) line = line.substring(0, ci);
                    line = line.trim();
                    if (line.length() > 0) {
                        try {
                            // 拆分,key=value 的配置格式
                            String name = null;
                            int i = line.indexOf('=');
                            if (i > 0) {
                                name = line.substring(0, i).trim();
                                line = line.substring(i + 1).trim();
                            }
                            if (line.length() > 0) {
                                loadClass(extensionClasses, resourceURL, Class.forName(line, true, classLoader), name);
                            }
                        } catch (Throwable t) {
                            // 发生异常,记录到异常集合
                            IllegalStateException e = new IllegalStateException("Failed to load extension class(interface: " + type + ", class line: " + line + ") in " + resourceURL + ", cause: " + t.getMessage(), t);
                            exceptions.put(line, e);
                        }
                    }
                }
            } finally {
                reader.close();
            }
        } catch (Throwable t) {
            logger.error("Exception when load extension class(interface: " +
                    type + ", class file: " + resourceURL + ") in " + resourceURL, t);
        }
    }

    private void loadClass(Map<String, Class<?>> extensionClasses, java.net.URL resourceURL, Class<?> clazz, String name) throws NoSuchMethodException {
        if (!type.isAssignableFrom(clazz)) {
            throw new IllegalStateException("Error when load extension class(interface: " +
                    type + ", class line: " + clazz.getName() + "), class "
                    + clazz.getName() + "is not subtype of interface.");
        }
        if (clazz.isAnnotationPresent(Adaptive.class)) {
            // 缓存自适应拓展对象的类到 `cachedAdaptiveClass`
            if (cachedAdaptiveClass == null) {
                cachedAdaptiveClass = clazz;
            } else if (!cachedAdaptiveClass.equals(clazz)) {
                throw new IllegalStateException("More than 1 adaptive class found: "
                        + cachedAdaptiveClass.getClass().getName()
                        + ", " + clazz.getClass().getName());
            }
        } else if (isWrapperClass(clazz)) {
            // 缓存拓展 Wrapper 实现类到 `cachedWrapperClasses`
            Set<Class<?>> wrappers = cachedWrapperClasses;
            if (wrappers == null) {
                cachedWrapperClasses = new ConcurrentHashSet<Class<?>>();
                wrappers = cachedWrapperClasses;
            }
            wrappers.add(clazz);
        } else {
         // 未配置拓展名,自动生成。主要用于兼容 Java SPI 的配置。
            clazz.getConstructor();
            if (name == null || name.length() == 0) {
                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 (names != null && names.length > 0) {
                // 缓存 @Activate 到 `cachedActivates` 。
                Activate activate = clazz.getAnnotation(Activate.class);
                if (activate != null) {
                    cachedActivates.put(names[0], activate);
                }
                for (String n : names) {
                    // 缓存到 `cachedNames`
                    if (!cachedNames.containsKey(clazz)) {
                        cachedNames.put(clazz, n);
                    }
                    Class<?> c = extensionClasses.get(n);
                    if (c == null) {
                        extensionClasses.put(n, clazz);
                    } else if (c != clazz) {
                        throw new IllegalStateException("Duplicate extension " + type.getName() + " name " + n + " on " + c.getName() + " and " + clazz.getName());
                    }
                }
            }
        }
    }

自动激活扩展

在dubbo中,某些组件可以同时有多个实现同时加载时,就可以通过@Activate注解自动激活,常见的自动激活扩展,如过滤器Filter,有顺序要求,提供了三个排序属性,before、after和order。还有一些过滤条件,主要是通过分组和key,如provider和consumer的过滤逻辑可能就不一样.
获取激活的扩展对象:

#getActivateExtension(com.alibaba.dubbo.common.URL, String, String)
     */
    public List<T> getActivateExtension(URL url, String key) {
        return getActivateExtension(url, key, null);
    }
    public List<T> getActivateExtension(URL url, String[] values, String group) {
        List<T> exts = new ArrayList<T>();
        List<String> names = values == null ? new ArrayList<String>(0) : Arrays.asList(values);
        // 处理自动激活的拓展对象们
        // 判断不存在配置 `"-name"` 。例如,<dubbo:service filter="-default" /> ,代表移除所有默认过滤器。
        if (!names.contains(Constants.REMOVE_VALUE_PREFIX + Constants.DEFAULT_KEY)) {
            getExtensionClasses();
            for (Map.Entry<String, Activate> entry : cachedActivates.entrySet()) {
                String name = entry.getKey();
                Activate activate = entry.getValue();
                //匹配分组
                if (isMatchGroup(group, activate.group())) {
                    // 获得拓展对象
                    T ext = getExtension(name);
                    if (!names.contains(name)
                            // 判断是否配置移除。例如 <dubbo:service filter="-monitor" />,则 MonitorFilter 会被移除
                            && !names.contains(Constants.REMOVE_VALUE_PREFIX + name)
                            // 判断是否激活
                            && isActive(activate, url)) {
                        exts.add(ext);
                    }
                }
            }
            // 排序
            Collections.sort(exts, ActivateComparator.COMPARATOR);
        }
        // 处理自定义配置的拓展对象们。例如在 <dubbo:service filter="myTest" /> ,代表需要加入 myTestFilter
        List<T> usrs = new ArrayList<T>();
        for (int i = 0; i < names.size(); i++) {
            String name = names.get(i);
            if (!name.startsWith(Constants.REMOVE_VALUE_PREFIX)
                    && !names.contains(Constants.REMOVE_VALUE_PREFIX + name)) {
                // 将配置的自定义在自动激活的拓展对象们前面。例如,<dubbo:service filter="demo,default,demo2" /> ,则 DemoFilter 就会放在默认的过滤器前面。
                if (Constants.DEFAULT_KEY.equals(name)) {
                    if (!usrs.isEmpty()) {
                        exts.addAll(0, usrs);
                        usrs.clear();
                    }
                } else {
                    // 获得拓展对象
                    T ext = getExtension(name);
                    usrs.add(ext);
                }
            }
        }
        // 添加到结果集
        if (!usrs.isEmpty()) {
            exts.addAll(usrs);
        }
        return exts;
    }

这个方法主要工作就是从之前加载配置时缓存的cachedActivates中过滤符合条件的自动激活实例,并根据@Activate的排序规则排序

自动装配(IOC注入)

在创建自适应实例时,都会调用ExtensionLoader的injectExtension方法:

 private T injectExtension(T instance) {
        try {
            if (objectFactory != null) {
            //反射获得所有方法
                for (Method method : instance.getClass().getMethods()) {
                    // setting && public 方法
                    if (method.getName().startsWith("set")
                            && method.getParameterTypes().length == 1
                            && Modifier.isPublic(method.getModifiers())) {
                        /**
                         * Check {@link DisableInject} to see if we need auto injection for this property
                         */
                        if (method.getAnnotation(DisableInject.class) != null) {
                            continue;
                        }
                        // 获得属性的类型
                        Class<?> pt = method.getParameterTypes()[0];
                        try {
                            //获得属性
                            String property = method.getName().length() > 3 ? method.getName().substring(3, 4).toLowerCase() + method.getName().substring(4) : "";
                            // 获得属性值
                            Object object = objectFactory.getExtension(pt, property);
                            // 设置属性值
                            if (object != null) {
                                method.invoke(instance, object);
                            }
                        } catch (Exception e) {
                            logger.error("fail to inject via method " + method.getName()
                                    + " of interface " + type.getName() + ": " + e.getMessage(), e);
                        }
                    }
                }
            }
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
        }
        return instance;
    }

其中objectFactory.getExtension(pt, property)就是获取IOC实例。就是检测扩展实现类有没有通过set方法设置的属性,如果有,就通过ExtensionFactory加载而设置。
ExtensionFactory 自身也是拓展接口,基于 Dubbo SPI 加载具体拓展实现类。

@SPI
public interface ExtensionFactory {

    /**
     * Get extension.
     *
     * @param type object type.
     * @param name object name.
     * @return object instance.
     */
    <T> T getExtension(Class<T> type, String name);

}

objectFactory是在构造ExtensionLoader时必须要创建的:是ExtensionFactory的自适应实例。

 private ExtensionLoader(Class<?> type) {
        this.type = type;
        objectFactory = (type == ExtensionFactory.class ? null : ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension());
    }

来看下AdaptiveExtensionFactory:

public class AdaptiveExtensionFactory implements ExtensionFactory {
    /**
     * ExtensionFactory 拓展对象集合
     */
    private final List<ExtensionFactory> factories;

    public AdaptiveExtensionFactory() {
        //使用 ExtensionLoader 加载拓展对象实现类。
        ExtensionLoader<ExtensionFactory> loader = ExtensionLoader.getExtensionLoader(ExtensionFactory.class);
        List<ExtensionFactory> list = new ArrayList<ExtensionFactory>();
        for (String name : loader.getSupportedExtensions()) {
            list.add(loader.getExtension(name));
        }
        factories = Collections.unmodifiableList(list);
    }

    @Override
    public <T> T getExtension(Class<T> type, String name) {
        // 遍历工厂数组,直到获得到属性
        for (ExtensionFactory factory : factories) {
            T extension = factory.getExtension(type, name);
            if (extension != null) {
                return extension;
            }
        }
        return null;
    }

}

AdaptiveExtensionFactory维护了ExtensionFatocry的非自适应扩展实例数组,扩展实现类的自动装配就是通过对象工厂获取。这些扩展实例其实就两个:SpiExtensionFactory和SpringExtensionFactory。
ExtensionFactory的类实现体系:
ExtensionFactory的类实现体系

SpringExtensionFactory.getExtension方法:

    public <T> T getExtension(Class<T> type, String name) {
        for (ApplicationContext context : contexts) {
            if (context.containsBean(name)) {
                Object bean = context.getBean(name);
                if (type.isInstance(bean)) {
                    return (T) bean;
                }
            }
        }

        logger.warn("No spring extension (bean) named:" + name + ", try to find an extension (bean) of type " + type.getName());

        if (Object.class == type) {
            return null;
        }

        for (ApplicationContext context : contexts) {
            try {
                return context.getBean(type);
            } catch (NoUniqueBeanDefinitionException multiBeanExe) {
                logger.warn("Find more than 1 spring extensions (beans) of type " + type.getName() + ", will stop auto injection. Please make sure you have specified the concrete parameter type and there's only one extension of that type.");
            } catch (NoSuchBeanDefinitionException noBeanExe) {
                if (logger.isDebugEnabled()) {
                    logger.debug("Error when get spring extension(bean) for type:" + type.getName(), noBeanExe);
                }
            }
        }

        logger.warn("No spring extension (bean) named:" + name + ", type:" + type.getName() + " found, stop get bean.");

        return null;
    }

遍历 contexts ,调用其 ApplicationContext#getBean(name) 方法和ApplicationContext#getBean(type) 获得 Bean 对象,直到成功并且值类型正确。

SpiExtensionFactory.getExtension方法:

    @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()) {
                return loader.getAdaptiveExtension();
            }
        }
        return null;
    }

[外链图片转存失败(img-82fnwHjS-1564366186551)(media/15497013856273/15497828409936.jpg)]

自动包装

获取扩展点:getExtension

 public T getExtension(String name) {
        if (name == null || name.length() == 0)
            throw new IllegalArgumentException("Extension name == null");
        if ("true".equals(name)) {
            // 查找 默认的 拓展对象
            return getDefaultExtension();
        }
        // 从缓存中获得对应的拓展对象
        Holder<Object> holder = cachedInstances.get(name);
        if (holder == null) {
            cachedInstances.putIfAbsent(name, new Holder<Object>());
            holder = cachedInstances.get(name);
        }
        Object instance = holder.get();
        if (instance == null) {
            synchronized (holder) {
                instance = holder.get();
                if (instance == null) {
                    // 从缓存中未获取到,进行创建缓存对象。
                    instance = createExtension(name);
                    //设置创建对象到缓存中
                    holder.set(instance);
                }
            }
        }
        return (T) instance;
    }

创建拓展名的拓展对象:createExtension(name)

  private T createExtension(String name) {
        // 获得拓展名对应的拓展实现类
        Class<?> clazz = getExtensionClasses().get(name);
        if (clazz == null) {
            throw findException(name);
        }
        try {
            // 从缓存中,获得拓展对象。
            T instance = (T) EXTENSION_INSTANCES.get(clazz);
            if (instance == null) {
                // 当缓存不存在时,创建拓展对象,并添加到缓存中。
                EXTENSION_INSTANCES.putIfAbsent(clazz, clazz.newInstance());
                instance = (T) EXTENSION_INSTANCES.get(clazz);
            }
            // 注入依赖的属性
            injectExtension(instance);
            // 创建 Wrapper 拓展对象
            Set<Class<?>> wrapperClasses = cachedWrapperClasses;
            if (wrapperClasses != null && !wrapperClasses.isEmpty()) {
                for (Class<?> wrapperClass : wrapperClasses) {
                    instance = injectExtension((T) wrapperClass.getConstructor(type).newInstance(instance));
                }
            }
            return instance;
        } catch (Throwable t) {
            throw new IllegalStateException("Extension instance(name: " + name + ", class: " +
                    type + ")  could not be instantiated: " + t.getMessage(), t);
        }
    }

看下官网对Wrapper得解释:

Wrapper 类同样实现了扩展点接口,但是 Wrapper 不是扩展点的真正实现。它的用途主要是用于从 ExtensionLoader 返回扩展点时,包装在真正的扩展点实现外。即从 ExtensionLoader 中返回的实际上是 Wrapper 类的实例,Wrapper 持有了实际的扩展点实现类。

扩展点的 Wrapper 类可以有多个,也可以根据需要新增。

通过 Wrapper 类可以把所有扩展点公共逻辑移至 Wrapper 中。新加的 Wrapper 在所有的扩展点上添加了逻辑,有些类似 AOP,即 Wrapper 代理了扩展点。

例如:ListenerExporterWrapper、ProtocolFilterWrapper

先到这里喽~完

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值