前面提到了java的SPI机制,现在我们看看dubbo的SPI机制。
HelloSpiService接口,要加上@SPI注解

@SPI
public interface HelloSpiService {
    void sayHello();
}

实现类HelloSpiServiceImpl同java的SPI机制
在资源META-INF/dubbo文件下创建一个文件com.learn.dubbo.spi.HelloSpiService,文件内容不同与java的SPI的是用键值对。这样的好处是只加载需要的扩展点,节约资源。

helloSpiService=com.learn.dubbo.spi.impl.HelloSpiServiceImpl

测试代码:

public class DubboTest {
    public static void main(String[] args) {
        ExtensionLoader<HelloSpiService> extensionLoader =
                ExtensionLoader.getExtensionLoader(HelloSpiService.class);
        HelloSpiService helloSpiService = extensionLoader.getExtension("helloSpiService");
        helloSpiService.sayHello();
    }
}

运行结果如下:
image.png

源码分析

getExtensionLoader

主要做的事情:

  1. 对type判断,比如是否为空,是否是接口,是否是SPI注解
  2. 返回一个ExtensionLoader对象
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) {
        EXTENSION_LOADERS.putIfAbsent(type, new ExtensionLoader<T>(type));
        loader = (ExtensionLoader<T>) EXTENSION_LOADERS.get(type);
    }
    return loader;
}

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

getExtension

获取扩展实例,没有则创建

public T getExtension(String name) {
    if (StringUtils.isEmpty(name)) {
        throw new IllegalArgumentException("Extension name == null");
    }
    if ("true".equals(name)) {
        // 获取默认的扩展点
        return getDefaultExtension();
    }
    // 获取或创建Holder对象
    final Holder<Object> holder = getOrCreateHolder(name);
    // holder对象没有值,则创建拓展实例
    Object instance = holder.get();
    if (instance == null) {
        synchronized (holder) {
            instance = holder.get();
            if (instance == null) {
                instance = createExtension(name);
                holder.set(instance);
            }
        }
    }
    // 返回拓展实例
    return (T) instance;
}

private Holder<Object> getOrCreateHolder(String name) {
    // 缓存没有,则创建完放入缓存
    Holder<Object> holder = cachedInstances.get(name);
    if (holder == null) {
        // putIfAbsent防止一个name对应多个Holder
        cachedInstances.putIfAbsent(name, new Holder<>());
        holder = cachedInstances.get(name);
    }
    return holder;
}

createExtension

从配置信息获取类信息,判断是否实例化过,没有则实例化对象放入缓存

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);
        Set<Class<?>> wrapperClasses = cachedWrapperClasses;
        if (CollectionUtils.isNotEmpty(wrapperClasses)) {
            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 + ") couldn't be instantiated: " + t.getMessage(), t);
    }
}

getExtensionClasses

先从缓存获取,缓存获取不到,再调用loadExtensionClasses从配置文件获取信息实例化

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;
}

loadExtensionClasses

验证SPI注解内容,再从文件夹读取配置文件,我们配置的META-INF/dubbo/就是这里读取的。

private Map<String, Class<?>> loadExtensionClasses() {
    // 验证SPI注解内容
    cacheDefaultExtensionName();
    // 加载指定文件夹下的配置文件
    Map<String, Class<?>> extensionClasses = new HashMap<>();
    loadDirectory(extensionClasses, DUBBO_INTERNAL_DIRECTORY, type.getName());
    loadDirectory(extensionClasses, DUBBO_INTERNAL_DIRECTORY, type.getName().replace("org.apache", "com.alibaba"));
    loadDirectory(extensionClasses, DUBBO_DIRECTORY, type.getName());
    loadDirectory(extensionClasses, DUBBO_DIRECTORY, type.getName().replace("org.apache", "com.alibaba"));
    loadDirectory(extensionClasses, SERVICES_DIRECTORY, type.getName());
    loadDirectory(extensionClasses, SERVICES_DIRECTORY, type.getName().replace("org.apache", "com.alibaba"));
    return extensionClasses;
}

loadDirectory

通过文件路径获取资源路径

private void loadDirectory(Map<String, Class<?>> extensionClasses, String dir, String type) {
    // 获取文件路径
    String fileName = dir + type;
    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 occurred when loading extension class (interface: " +
                type + ", description file: " + fileName + ").", t);
    }
}

loadResource

读取文件内容,解析后,实例化对象并缓存。

private void loadResource(Map<String, Class<?>> extensionClasses, ClassLoader classLoader, java.net.URL resourceURL) {
    try {
        // 读取文件内容
        try (BufferedReader reader = new BufferedReader(new InputStreamReader(resourceURL.openStream(), StandardCharsets.UTF_8))) {
            String line;
            while ((line = reader.readLine()) != null) {
                // 如果有#号,只读取前面部分,#后面是注释
                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);
                    }
                }
            }
        }
    } catch (Throwable t) {
        logger.error("Exception occurred when loading extension class (interface: " +
                type + ", class file: " + resourceURL + ") in " + resourceURL, t);
    }
}

loadClass

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 occurred when loading extension class (interface: " +
                type + ", class line: " + clazz.getName() + "), class "
                + clazz.getName() + " is not subtype of interface.");
    }
    // Adaptive注解
    if (clazz.isAnnotationPresent(Adaptive.class)) {
        cacheAdaptiveClass(clazz);
    // 是否Wrapper类型
    } else if (isWrapperClass(clazz)) {
        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);
            }
        }
    }
}

大军
847 声望183 粉丝

学而不思则罔,思而不学则殆