Dubbo SPI是什么?Dubbo SPI如何实现?我们从中能够学习到什么?

Dubbo SPI是什么

Dubbo SPI(Service Provider Interface),用于根据名称获取Interface接口的实现类,根据条件激活Interface接口的实现类集合,即一组实现类。并且是根据JAVA SPI扩展而来,具有如下特性:

  1. 按需要加载Interface接口的实现类,JDK 标准的 SPI 会一次性实例化扩展点所有实现,如果有扩展实,现初始化很耗时,但如果没用上也加载,会很浪费资源。
  2. 增加了对扩展点 IoC 和 AOP 的支持,一个扩展点可以直接 setter 注入其它扩展点。

Dubbo SPI获取扩展实现类的大致入流如下:

在激活实现类集合时,也是根据SPI机制逐个获取实现类,所以我们重点分析如何根据SPI机制获取扩展实现类即可。

Dubbo SPI如何实现

从配置文件获取扩展实现类配置

根据名称获取扩展实现类时,首先需要从配置文件加载名称与扩展实现类的映射配置,从不同位置的文件加载。实例,以加载dubbo中自定义实现的线程池ThreadPool为例,在dubbo中,定义ThreadPool线程池的接口,在基于dubbo SPI的机制中,可以根据name为fixed,cached,limited,eager分别获取到对应的实现类FixedThreadPool,CachedThreadPool,LimitedThreadPool,EagerThreadPool。线程池的其具体实现可以参考为什么要使用线程池?dubbo是如何扩展的?,其SPI文件配置如图:

配置文件以Interface全限定名称为文件名,配置内容以name=实现类的形式配置,其源码如下:

fixed=org.apache.dubbo.common.threadpool.support.fixed.FixedThreadPool
cached=org.apache.dubbo.common.threadpool.support.cached.CachedThreadPool
limited=org.apache.dubbo.common.threadpool.support.limited.LimitedThreadPool
eager=org.apache.dubbo.common.threadpool.support.eager.EagerThreadPool

ExtensionLoader调用getExtension(String name)获取扩展实现类,初次加载会调用getExtensionClasses从配置文件获取扩展实现类的Class与名称的配置。其源码如下:

// 根据name获取扩展实现类
// ExtensionLoader.class    
public T getExtension(String name) {
        if (StringUtils.isEmpty(name)) {
            throw new IllegalArgumentException("Extension name == null");
        }
        if ("true".equals(name)) {
            return getDefaultExtension();
        }
        final Holder<Object> holder = getOrCreateHolder(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;
    }

// 根据name生成扩展实现类
// ExtensionLoader.class  
private T createExtension(String name) {
        // getExtensionClasses 获取扩展实现类的Class配置
        Class<?> clazz = getExtensionClasses().get(name);
        if (clazz == null) {
            throw findException(name);
        }
        try {
            T instance = (T) EXTENSION_INSTANCES.get(clazz);
            if (instance == null) {
                // 通过反射,使用Class生成实例对象
                EXTENSION_INSTANCES.putIfAbsent(clazz, clazz.newInstance());
                instance = (T) EXTENSION_INSTANCES.get(clazz);
            }
            injectExtension(instance);
            Set<Class<?>> wrapperClasses = cachedWrapperClasses;
            if (CollectionUtils.isNotEmpty(wrapperClasses)) {
                for (Class<?> wrapperClass : wrapperClasses) {
                    // 实例化wrapper对象
                    instance = injectExtension((T) wrapperClass.getConstructor(type).newInstance(instance));
                }
            }
            // IOC机制使用setter方式注入属性实例对象
            initExtension(instance);
            return instance;
        } catch (Throwable t) {
            throw new IllegalStateException("Extension instance (name: " + name + ", class: " +
                    type + ") couldn't be instantiated: " + t.getMessage(), t);
        }
    }


// 从配置文件获取扩展实现类的Class与名称配置
// ExtensionLoader.class  
private Map<String, Class<?>> getExtensionClasses() {
        Map<String, Class<?>> classes = cachedClasses.get();
        if (classes == null) {
            synchronized (cachedClasses) {
                classes = cachedClasses.get();
                if (classes == null) {
                    classes = loadExtensionClasses();
                    cachedClasses.set(classes);
                }
            }
        }
        return classes;
    }


// 加载扩展实现配置
// ExtensionLoader.class  
private Map<String, Class<?>> loadExtensionClasses() {
        cacheDefaultExtensionName();

        Map<String, Class<?>> extensionClasses = new HashMap<>();

        for (LoadingStrategy strategy : strategies) {
            // 从指定文件路径加载
            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;
    }

dubbo定义LoadingStrategy加载策略接口,在不同文件路径的配置文件,其实现类如下:

  • DubboExternalLoadingStrategy,扩展加载策略,从"META-INF/dubbo/external/"文件路径加载。
  • DubboInternalLoadingStrategy,内部加载策略,从"META-INF/dubbo/internal/"文件路径加载。
  • DubboLoadingStrategy,用户自定义加载策略,从"META-INF/dubbo/"文件路径加载。
  • ServicesLoadingStrategy,JAVA SPI加载策略,从"META-INF/services/"文件路径加载。

扩展实现类的初始化

获取到扩展实现类的配置时,dubbo使用Class对象,用反射机制生成具体实现类。如果,是使用装饰模式的wraper装饰类,则使用带有指定接口类型的构造函数生成实现类。如果,扩展实现类包含其他实现类的属性,则使用IOC机制,基于setter属性设置的机制设置属性。其源码如下:

// 根据name生成扩展现类实例
//  ExtensionLoader.class   
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) {
                // 使用Class的默认构造函数反射生成实例对象
                EXTENSION_INSTANCES.putIfAbsent(clazz, clazz.newInstance());
                instance = (T) EXTENSION_INSTANCES.get(clazz);
            }
            // IOC机制,setter方式设置属性值
            injectExtension(instance);
            Set<Class<?>> wrapperClasses = cachedWrapperClasses;
            if (CollectionUtils.isNotEmpty(wrapperClasses)) {
                for (Class<?> wrapperClass : wrapperClasses) {
                    // 如果是wrapper装饰类,使用Class的指定type构造函数反射生成实例对象
                    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);
        }
    }
// 调用set方法设置objectFactory生成的属性值
//  ExtensionLoader.class   
private T injectExtension(T instance) {

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

        try {
            for (Method method : instance.getClass().getMethods()) {
                if (!isSetter(method)) {
                    continue;
                }
                /**
                 * 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];
                if (ReflectUtils.isPrimitives(pt)) {
                    continue;
                }

                try {
                    String property = getSetterProperty(method);
                    // objectFactory获取指定名称的扩展实现类
                    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中,ExtensionLoader初始化时,会根据@Adaptive使用javassist动态生成ExtensionFactory代理类。该ExtensionFactory代理类,能够根据URL传递的name参数动态获取指定的实现类。具体的自适应机制可以参考官网地址自适应扩展机制原理,其部分源码如下:

// ExtensionLoader.class
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!");
        }
        if (!withExtensionAnnotation(type)) {
            throw new IllegalArgumentException("Extension type (" + type +
                    ") is not an extension, because it is NOT annotated with @" + SPI.class.getSimpleName() + "!");
        }

        ExtensionLoader<T> loader = (ExtensionLoader<T>) EXTENSION_LOADERS.get(type);
        if (loader == null) {
            初始化ExtensionLoader
            EXTENSION_LOADERS.putIfAbsent(type, new ExtensionLoader<T>(type));
            loader = (ExtensionLoader<T>) EXTENSION_LOADERS.get(type);
        }
        return loader;
    }

// 初始化ExtensionLoader
private ExtensionLoader(Class<?> type) {
        this.type = type;
        objectFactory = (type == ExtensionFactory.class ? null : 
// 根据Adaptive注解标识,使用javsssit动态代理生成具体的代理类
ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension());
    }

我们从中能够学习到什么

  1. IOC:类似于spring的属性注入简化版,能够根据自适应扩展机制,动态的根据URL参数设置属性值。
  2. 动态代理,类似AOP,通过@Adaptive注解,标识代理的方法,使用Javassit动态编译代理逻辑。在dubbo中,实现能够根据URL参数获取指定name,然后通过name获取对应的扩展实现类。具体实例可以参考代理(Proxy)是什么?为什么要使用代理模式?Spring与Dubbo如何运用代理模式的?
  3. 反射,在读取扩展实现的配置后,适应累加器读转换为JVM中的Class对象,通过反射机制创建无参数的或者装饰模式的实例对象。
  4. 装饰模式,具体实现可以参考装饰器模式-Mybatis教你如何玩

猜你喜欢

转载自blog.csdn.net/new_com/article/details/106844658
今日推荐