学习手写Dubbo中的SPI

Dubbo的SPI是什么

SPI的全称是Service Provider Interface,是Java提供的一套用来被第三方实现或者扩展的API,SPI的作用就是为这些被扩展的API寻找服务实现。

Dubbo核心特点

  • SPI机制(按需加载)
  • 自适应扩展点
  • IOC和AOP
  • Dubbo怎么和Spring集成

Dubbo配置文件约定

  • META-INF/services/ 目录:该目录下的 SPI 配置文件是为了用来兼容 Java SPI 。
  • META-INF/dubbo/ 目录:该目录存放用户自定义的 SPI 配置文件。
  • META-INF/dubbo/internal/ 目录:该目录存放 Dubbo 内部使用的 SPI 配置文件。

Dubbo SPI源码实例

在这里插入图片描述

SPI注解

package com.spi.annotation;

import java.lang.annotation.*;

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({
    
    ElementType.TYPE})
public @interface SPI {
    
    
    /**
     * 扩展点名。
     */
    String value() default "";
}

加载扩展

package com.spi.loader;

import com.spi.annotation.SPI;
import com.spi.util.Holder;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.URL;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.regex.Pattern;

public class ExtensionLoader<T> {
    
    
    /**
     * 定义SPI文件的扫描路径,dubbo源码中设置了多个,我们这里只设置一个
     */
    private static final String DIRECTORY = "META-INF/dubbo/";

    /**
     * 分割SPI上默认拓展点字符串用的
     */
    private static final Pattern NAME_SEPARATOR = Pattern.compile("\\s*[,]+\\s*");

    /**
     * 拓展点加载器的缓存
     */
    private static final ConcurrentMap<Class<?>, ExtensionLoader<?>> EXTENSION_LOADERS =
            new ConcurrentHashMap<Class<?>, ExtensionLoader<?>>();

    /**
     * 拓展点的缓存
     */
    private static final ConcurrentMap<Class<?>, Object> EXTENSION_INSTANCES = new ConcurrentHashMap<Class<?>, Object>();

    /**
     * 接口的class
     */
    private final Class<?> type;

    /**
     * 接口SPI默认的实现名(就是把接口上填的默认值)
     */
    private String cachedDefaultName;

    /**
     * 异常记录
     */
    private Map<String, IllegalStateException> exceptions = new ConcurrentHashMap<String, IllegalStateException>();

    //这两个缓存文字比较难描述,debug或者搜索一下调用就知道是缓存什么的了
    private final Holder<Map<String, Class<?>>> cachedClasses = new Holder<Map<String, Class<?>>>();
    private final ConcurrentMap<String, Holder<Object>> cachedInstances = new ConcurrentHashMap<String, Holder<Object>>();


    private static <T> boolean withExtensionAnnotation(Class<T> type) {
    
    
        return type.isAnnotationPresent(SPI.class);
    }

    private ExtensionLoader(Class<T> type) {
    
    
        this.type = type;
    }

    public static <T> ExtensionLoader<T> getExtensionLoader(Class<T> type) {
    
    
        if (type == null)//1.拓展点类型非空判断
            throw new IllegalArgumentException("Extension type == null");
        if (!type.isInterface()) {
    
    //2.拓展点类型只能是接口
            throw new IllegalArgumentException("Extension type(" + type + ") is not interface!");
        }
        if (!withExtensionAnnotation(type)) {
    
    //3.需要添加spi注解,否则抛异常
            throw new IllegalArgumentException("Extension type(" + type +
                    ") is not extension, because WITHOUT @" + SPI.class.getSimpleName() + " Annotation!");
        }
        //从缓存EXTENSION_LOADERS中获取,如果不存在则新建后加入缓存
        //对于每一个拓展,都会有且只有一个ExtensionLoader与其对应
        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;
    }


    /**
     * 返回指定名字的扩展。如果指定名字的扩展不存在,则抛异常 {@link IllegalStateException}.
     *
     * @param name
     * @return
     */
    @SuppressWarnings("unchecked")
    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;
    }

    //根据获取到的拓展点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) {
    
    
                EXTENSION_INSTANCES.putIfAbsent(clazz, (T) clazz.newInstance());//反射生成对象
                instance = (T) EXTENSION_INSTANCES.get(clazz);
            }
            return instance;
        } catch (Throwable t) {
    
    
            throw new IllegalStateException("Extension instance(name: " + name + ", class: " +
                    type + ")  could not be instantiated: " + t.getMessage(), t);
        }
    }

    //获取拓展点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;
    }

    //1.设置接口默认的实现类名  2.加载文件
    private Map<String, Class<?>> loadExtensionClasses() {
    
    
        final SPI defaultAnnotation = type.getAnnotation(SPI.class);
        if (defaultAnnotation != null) {
    
    
            String value = defaultAnnotation.value();
            if (value != null && (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<?>>();
        loadFile(extensionClasses,DIRECTORY);
        return extensionClasses;
    }

    //加载解析spi配置文件,然后加入缓存
    public void loadFile(Map<String, Class<?>> extensionClasses, String dir) {
    
    
        String fileName = dir + type.getName();
        try {
    
    
            Enumeration<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 url = urls.nextElement();
                    try {
    
    
                        BufferedReader reader = new BufferedReader(new InputStreamReader(url.openStream(), "utf-8"));
                        try {
    
    
                            String line = null;
                            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) {
    
    
                                            Class<?> clazz = Class.forName(line, true, classLoader);
                                            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.");
                                            }
                                            extensionClasses.put(name, clazz);//加入缓存
                                        }//源码中还有其他的判断,这个版本暂不实现
                                    } catch (Throwable t) {
    
    
                                        IllegalStateException e = new IllegalStateException("Failed to load extension class(interface: " + type + ", class line: " + line + ") in " + url + ", cause: " + t.getMessage(), t);
                                        exceptions.put(line, e);
                                    }
                                }
                            } // end of while read lines
                        } finally {
    
    
                            reader.close();
                        }
                    } catch (Throwable t) {
    
    
                        //logger.error("Exception when load extension class(interface: " +
                        //        type + ", class file: " + url + ") in " + url, t);
                    }
                } // end of while urls
            }
        } catch (Throwable e) {
    
    
            //logger.error("Exception when load extension class(interface: " + type + ", description file: " + fileName + ").", e);
        }
    }

    //获取类加载器
    private static ClassLoader findClassLoader() {
    
    
        return ExtensionLoader.class.getClassLoader();
    }

    //获取默认拓展点
    public T getDefaultExtension() {
    
    
        getExtensionClasses();
        if (null == cachedDefaultName || cachedDefaultName.length() == 0
                || "true".equals(cachedDefaultName)) {
    
    
            return null;
        }
        return getExtension(cachedDefaultName);
    }

    //异常提示
    private IllegalStateException findException(String name) {
    
    
        for (Map.Entry<String, IllegalStateException> entry : exceptions.entrySet()) {
    
    
            if (entry.getKey().toLowerCase().contains(name.toLowerCase())) {
    
    
                return entry.getValue();
            }
        }
        StringBuilder buf = new StringBuilder("No such extension " + type.getName() + " by name " + name);

        int i = 1;
        for (Map.Entry<String, IllegalStateException> entry : exceptions.entrySet()) {
    
    
            if (i == 1) {
    
    
                buf.append(", possible causes: ");
            }

            buf.append("\r\n(");
            buf.append(i++);
            buf.append(") ");
            buf.append(entry.getKey());
            buf.append(":\r\n");
            buf.append(entry.getValue().toString());
        }
        return new IllegalStateException(buf.toString());
    }
}
package com.spi.util;

public class Holder<T> {
    
    
    private volatile T value;

    public void set(T value) {
    
    
        this.value = value;
    }

    public T get() {
    
    
        return value;
    }
}

测试类

package com;

import com.spi.loader.ExtensionLoader;
import com.spi.animal.Animal;

/**
 * Hello world!
 *
 */
public class App 
{
    
    
    public static void main( String[] args )
    {
    
    
        //获取默认实现类
        Animal defaultExtension = ExtensionLoader.
                getExtensionLoader(Animal.class).
                getDefaultExtension();
        defaultExtension.hello();

        //指定特定的实现类
        Animal animal = ExtensionLoader.
                getExtensionLoader(Animal.class).
                getExtension("cat");
        animal.hello();
    }
}

执行结果

在这里插入图片描述

源码地址

https://gitee.com/myzjspace/dubbo-spi

临摹:https://www.jianshu.com/p/0185c5229b7d

猜你喜欢

转载自blog.csdn.net/xiaowanzi_zj/article/details/121728270