2Dubbo的SPI机制1SPI简单分析

5次阅读

共计 6418 个字符,预计需要花费 17 分钟才能阅读完成。

1、Dubbo 的 SPI 例子

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

public class OptimusPrime implements Robot{
    @Override
    public void sayHello() {System.out.println("Hello, I am Optimus Prime.");
    }
}

public class Bumblebee implements Robot{
    @Override
    public void sayHello() {System.out.println("Hello, I am Bumblebee.");
    }
}
public class DubboSPITest {

    @Test
    public void sayHelloDubbo() throws Exception {ExtensionLoader<Robot> extensionLoader = ExtensionLoader.getExtensionLoader(Robot.class);
        Robot optimusPrime = extensionLoader.getExtension("optimusPrime");
        optimusPrime.sayHello();
        Robot bumblebee = extensionLoader.getExtension("bumblebee");
        bumblebee.sayHello();}
}
 输出:
Hello, I am Optimus Prime.
Hello, I am Bumblebee.

2、Dubbo 的 SPI 源码分析

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

    // 从缓存中获取与拓展类对应的 ExtensionLoader
    ExtensionLoader<T> loader = (ExtensionLoader<T>) EXTENSION_LOADERS.get(type);
    if (loader == null) {// 若缓存未命中, 则创建一个新的实例, 先简单看下 new ExtensionLoader<T>(type)
        EXTENSION_LOADERS.putIfAbsent(type, new ExtensionLoader<T>(type));
        loader = (ExtensionLoader<T>) EXTENSION_LOADERS.get(type);
    }
    return loader;
}
 private ExtensionLoader(Class<?> type) {
    this.type = type;
    // 这里的 type 是 Robot.class, 所以会执行后面的代码, 加载并创建 SpiExtensionFactory 和 SpringExtensionFactory,
    // 后面再分析
    objectFactory = (type == ExtensionFactory.class ? null : 
                   ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension());
}
Robot optimusPrime = extensionLoader.getExtension("optimusPrime");
public T getExtension(String name) {if ("true".equals(name)) {return getDefaultExtension();
    }
    // Holder 也是用于持有对象的, 用作缓存
    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) {// 创建拓展实例, 下面分析 createExtension(name)
                instance = createExtension(name);
                holder.set(instance);
            }
        }
    }
    return (T) instance;
}
private T createExtension(String name) {
    // 从配置文件中加载所有的拓展类, 可得到“配置项名称”到“配置类”的映射关系表
    // 加载完后根据 name 获取, 得到形如 com.alibaba.dubbo.demo.provider.spi.OptimusPrime
    // 待会重点分析 getExtensionClasses(), 删去了一些非关键代码
    Class<?> clazz = getExtensionClasses().get(name);
    try {
        // 也是尝试先从缓存获取, 获取不到通过反射创建一个并放到缓存中
        T instance = (T) EXTENSION_INSTANCES.get(clazz);
        if (instance == null) {EXTENSION_INSTANCES.putIfAbsent(clazz, clazz.newInstance());
            instance = (T) EXTENSION_INSTANCES.get(clazz);
        }
        // 依赖注入和 cachedWrapperClasses, 后面分析
        injectExtension(instance);
        Set<Class<?>> wrapperClasses = cachedWrapperClasses;
        if (wrapperClasses != null && !wrapperClasses.isEmpty()) {for (Class<?> wrapperClass : wrapperClasses) {instance = injectExtension((T) wrapperClass.getConstructor(type).newInstance(instance));
           }
        }
        return instance;
    } 
}
 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;
}
private Map<String, Class<?>> loadExtensionClasses() {
    // 获取 SPI 注解, 这里的 type 是在调用 getExtensionLoader 方法时传入的
    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) {// 抛异常}
            // 获取 @SPI 注解中的值, 并缓存起来, 可以关注下, 后面会用到
            if (names.length == 1) cachedDefaultName = names[0];
        }
    }

    Map<String, Class<?>> extensionClasses = new HashMap<String, Class<?>>();
    // 加载指定文件夹下的配置文件,META-INF/services/、META-INF/dubbo/、META-INF/dubbo/internal/
    loadDirectory(extensionClasses, DUBBO_INTERNAL_DIRECTORY);
    // 我是放在这个目录下的
    loadDirectory(extensionClasses, DUBBO_DIRECTORY);
    loadDirectory(extensionClasses, SERVICES_DIRECTORY);
    return extensionClasses;
}
private void loadDirectory(Map<String, Class<?>> extensionClasses, String dir) {
    // fileName 是 META-INF/dubbo/com.alibaba.dubbo.demo.provider.spi.Robot
    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()) {
                // 一个 resourceURL 就是一个文件
                java.net.URL resourceURL = urls.nextElement();
                loadResource(extensionClasses, classLoader, resourceURL);
            }
        }
    } 
}
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) {final int ci = line.indexOf('#');
                // 定位 #字符,# 之后的为注释, 跳过
                if (ci >= 0) line = line.substring(0, ci);
                line = line.trim();
                if (line.length() > 0) {
                    try {
                        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);
                        }
                    }
                }
            }
        }
    } 
}
private void loadClass(Map<String, Class<?>> extensionClasses, java.net.URL resourceURL, 
                                      Class<?> clazz, String name) throws NoSuchMethodException {
    // clazz 必须是 type 类型的, 否则抛异常
    if (!type.isAssignableFrom(clazz)) { }
    // 判断 clazz 是否为标注了 @Adaptive 注解, 后面分析
    if (clazz.isAnnotationPresent(Adaptive.class)) {if (cachedAdaptiveClass == null) {cachedAdaptiveClass = clazz;} else if (!cachedAdaptiveClass.equals(clazz)) {// 抛异常, 不能有多个标注有 @Adaptive 注解的类}
    }
    // 判断是否是 Wrapper 类型, 后面分析
    else if (isWrapperClass(clazz)) {
        Set<Class<?>> wrappers = cachedWrapperClasses;
        if (wrappers == null) {cachedWrapperClasses = new ConcurrentHashSet<Class<?>>();
            wrappers = cachedWrapperClasses;
        }
        wrappers.add(clazz);
    }
    // 程序进入此分支, 表明 clazz 是一个普通的拓展类,Robot 就是一个普通的拓展类
    else {
        // 检测 clazz 是否有默认的构造方法, 如果没有, 则抛出异常
        clazz.getConstructor();
        if (name == null || name.length() == 0) {name = findAnnotationName(clazz);
            if (name.length() == 0) {// 抛异常}
        }
        String[] names = NAME_SEPARATOR.split(name);
        if (names != null && names.length > 0) {Activate activate = clazz.getAnnotation(Activate.class);
            if (activate != null) {cachedActivates.put(names[0], activate);
            }
            for (String n : names) {if (!cachedNames.containsKey(clazz)) {cachedNames.put(clazz, n);
                }
                Class<?> c = extensionClasses.get(n);
                if (c == null) {
                    // 存储名称到 class 的映射关系, 这样就解析好了一行
                    extensionClasses.put(n, clazz);
                } else if (c != clazz) {// 抛异常}
            }
        }
    }
}

正文完
 0