Dubbo SPI

dubbo spi

SPI 全称为 Service Provider Interface,是一种服务发现机制。SPI 的本质是将接口实现类的全限定名配置在文件中,并由服务加载器读取配置文件,加载实现类。这样可以在运行时,动态为接口替换实现类。正因此特性,我们可以很容易的通过 SPI 机制为我们的程序提供拓展功能。SPI 机制在第三方框架中也有所应用,比如 Dubbo 就是通过 SPI 机制加载所有的组件。不过,Dubbo 并未使用 Java 原生的 SPI 机制,而是对其进行了增强,使其能够更好的满足需求。在 Dubbo 中,SPI 是一个非常重要的模块。基于 SPI,我们可以很容易的对 Dubbo 进行拓展

Dubbo 并未使用 Java SPI,而是重新实现了一套功能更强的 SPI 机制。Dubbo SPI 的相关逻辑被封装在了 ExtensionLoader 类中,通过 ExtensionLoader,我们可以加载指定的实现类。Dubbo SPI 所需的配置文件需放置在 META-INF/dubbo 路径下,配置内容如下。

optimusPrime = org.apache.spi.OptimusPrime
bumblebee = org.apache.spi.Bumblebee

与 Java SPI 实现类配置不同,Dubbo SPI 是通过键值对的方式进行配置,这样我们可以按需加载指定的实现类。另外,在测试 Dubbo SPI 时,需要在 Robot 接口上标注 @SPI 注解
在这里插入图片描述

service

@SPI(value = "impl")
public interface PrintService {

    public void printInfo();
}

public class PrintServiceImpl implements PrintService {

    @Override
    public void printInfo() {
       
        System.out.println("hello printInfo "+LocalDateTime.now());

    }

}
public class PrintServiceSecondImpl implements PrintService {

    @Override
    public void printInfo() {

        System.out.println("PrintServiceSecondImpl  "+LocalDateTime.now());

    }

}

META-INF/dubbo目录下

文件

com.ghgcn.dubbo.provider.service.PrintService

impl=com.ghgcn.dubbo.provider.service.impl.PrintServiceImpl
qq=com.ghgcn.dubbo.provider.service.impl.PrintServiceSecondImpl
* 加载
public class PrintServiceApplication {

    public static void main(String[] args) {
	//1.加载扩展加载器
    ExtensionLoader<PrintService> extensionLoader = ExtensionLoader.getExtensionLoader(PrintService.class);
    
     //获取指定的实现类
    PrintService implPrintService = extensionLoader.getExtension("impl");
    //调用
    implPrintService.printInfo();
        //获取指定的实现类
  PrintService qqPrintService = extensionLoader.getExtension("qq");
    //调用
  qqPrintService.printInfo();

    }

}


  • 加载getExtensionLoader
 @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 an interface!");
        }
        //没有注解SPI
        if (!withExtensionAnnotation(type)) {
            throw new IllegalArgumentException("Extension type (" + type +
                    ") is not an extension, because it is NOT annotated with @" + SPI.class.getSimpleName() + "!");
        }
		//ConcurrentMap<Class<?>, ExtensionLoader<?>> EXTENSION_LOADERS = new ConcurrentHashMap<>();   从map中获取
        ExtensionLoader<T> loader = (ExtensionLoader<T>) EXTENSION_LOADERS.get(type);
        //为空
        if (loader == null) {
            //就new 一个再次放进Map中
            EXTENSION_LOADERS.putIfAbsent(type, new ExtensionLoader<T>(type));
            //再次获取出来
            loader = (ExtensionLoader<T>) EXTENSION_LOADERS.get(type);
        }
        //返回
        return loader;
    }
  • getExtension方法 extensionLoader.getExtension(“impl”);
    在这里插入图片描述
	/**
	从配置的扩展类name到获得该类的实例化的过程
	*/
    public T getExtension(String name) {
        //这里是上面的impl 不能为空
        if (StringUtils.isEmpty(name)) {
            throw new IllegalArgumentException("Extension name == null");
        }
        //如果是true就获取默认的SPI扩展实现
        if ("true".equals(name)) {
            //1. 获取默认SPI扩展
            return getDefaultExtension();
        }
        //创建Holder 2. 
        final Holder<Object> holder = getOrCreateHolder(name);
        Object instance = holder.get();
        //双重较验
        if (instance == null) {
            synchronized (holder) {
                instance = holder.get();
                if (instance == null) {
                    //3. 根据名称创建SPI实现
                    instance = createExtension(name);
                    //设置值
                    holder.set(instance);
                }
            }
        }
        //返回实例
        return (T) instance;
    }

  1. getDefaultExtension加载默认实现

  2. getOrCreateHolder

  private Holder<Object> getOrCreateHolder(String name) {
      //从缓存中获取
        Holder<Object> holder = cachedInstances.get(name);
        if (holder == null) {
            //    private final ConcurrentMap<String, Holder<Object>> cachedInstances = new ConcurrentHashMap<>();   一个map  key是传进来的name,value是 holder
            //如果为空就new一个出来并放入缓存
            cachedInstances.putIfAbsent(name, new Holder<>());
            holder = cachedInstances.get(name);
        }
        return holder;
    }

holder

public class Holder<T> {

    private volatile T value;

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

    public T get() {
        return value;
    }

}
  • 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);
        }
    }
  1. getExtensionClasses 获取所有扩展
    private Map<String, Class<?>> getExtensionClasses() {
        //从缓存中拿map, 如果没有,就调用loadExtensionClasses
        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
    // synchronized in getExtensionClasses
    private Map<String, Class<?>> loadExtensionClasses() {
        //调用cacheDefaultExtensionName拿到默认实现类
        cacheDefaultExtensionName();

        Map<String, Class<?>> extensionClasses = new HashMap<>();
        //调用loadDirectory从几个文件下寻找扩展类配置文件
        //DUBBO_INTERNAL_DIRECTORY
        //DUBBO_DIRECTORY
        //SERVICES_DIRECTORY 
        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;
    }

  • cacheDefaultExtensionName

变量路径

    private static final String SERVICES_DIRECTORY = "META-INF/services/";

    private static final String DUBBO_DIRECTORY = "META-INF/dubbo/";

    private static final String DUBBO_INTERNAL_DIRECTORY = DUBBO_DIRECTORY + "internal/";

    private static final Pattern NAME_SEPARATOR = Pattern.compile("\\s*[,]+\\s*");
    private void cacheDefaultExtensionName() {
        //获取类型上的SPI注解
        final SPI defaultAnnotation = type.getAnnotation(SPI.class);
        //不为空
        if (defaultAnnotation != null) {
            //获取SPI上的注解, 如果有设置value值,则取出, 这个值是默认实现类噢
            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 impl SPI中的值
                    cachedDefaultName = names[0];
                    
                }
            }
        }
    }

就是将SPI注解的value取出来来对应默认的实现类

  • loadDirectory 方法
    private void loadDirectory(Map<String, Class<?>> extensionClasses, String dir, String type) {
        String fileName = dir + type;
        try {
            Enumeration<java.net.URL> urls;
            //获取 classLoader  阿里封装的获取 classLoader 的方法
            ClassLoader classLoader = findClassLoader();
            //判断是否为空
            if (classLoader != null) {
                // jdk的方法, 与java spi一样的噢
                urls = classLoader.getResources(fileName);
            } else {
                urls = ClassLoader.getSystemResources(fileName);
            }
            //用url获取到文件流
            if (urls != null) {
                while (urls.hasMoreElements()) {
                    //解析每一行, 将=号前面的赋值为name,后面的赋值为实现类的全限定路径
                    java.net.URL resourceURL = urls.nextElement();
                    //反射实例化每一行的实现类, 并调用loadClass方法实现对extensionClasses的最终赋值(它new了一个extensionClasses的map对象直到后面才进行赋值
                    loadResource(extensionClasses, classLoader, resourceURL);
                }
            }
        } catch (Throwable t) {
            logger.error("Exception occurred when loading extension class (interface: " +
                    type + ", description file: " + fileName + ").", t);
        }
    }

在这里插入图片描述

  • findClassLoader获取classLoader
private static ClassLoader findClassLoader() {
        return ClassUtils.getClassLoader(ExtensionLoader.class);
    }
  • 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 {
                            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 {
    //判断当type是不是当前的接口或者父类,不是就抛出异常
        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注解的类, 就把它放到cacheAdaptiveClass缓存中
        if (clazz.isAnnotationPresent(Adaptive.class)) {
            cacheAdaptiveClass(clazz);
        } 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);
                }
            }
//分割name, 因为配置文件中name可以有很多个,然后每个name对应赋值一个实现类对象(即使对象都相同)
            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);
                }
            }
        }
    }

判断是否是Adaptive等注解的类, 就把它放到对应的cacheAdaptiveClass等缓存中

//添加Adaptive注解类的缓存
   private void cacheAdaptiveClass(Class<?> clazz) {
        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());
        }
    }

cacheWrapperClass 添加缓存

  private void cacheWrapperClass(Class<?> clazz) {
        if (cachedWrapperClasses == null) {
            cachedWrapperClasses = new ConcurrentHashSet<>();
        }
        cachedWrapperClasses.add(clazz);
    }

分割name, 因为配置文件中name可以有很多个,然后每个name对应赋值一个实现类对象(即使对象都相同)

cacheActivateClass

 private void cacheActivateClass(Class<?> clazz, String name) {
        Activate activate = clazz.getAnnotation(Activate.class);
        if (activate != null) {
            cachedActivates.put(name, activate);
        } else {
            // support com.alibaba.dubbo.common.extension.Activate
            com.alibaba.dubbo.common.extension.Activate oldActivate = clazz.getAnnotation(com.alibaba.dubbo.common.extension.Activate.class);
            if (oldActivate != null) {
                cachedActivates.put(name, oldActivate);
            }
        }
    }

cacheName

   private void cacheName(Class<?> clazz, String name) {
        if (!cachedNames.containsKey(clazz)) {
            cachedNames.put(clazz, name);
        }
    }

saveInExtensionClass

  private void saveInExtensionClass(Map<String, Class<?>> extensionClasses, Class<?> clazz, String name) {
        Class<?> c = extensionClasses.get(name);
        if (c == null) {
            //如果为null就放入缓存
            extensionClasses.put(name, clazz);
        } else if (c != clazz) {
            throw new IllegalStateException("Duplicate extension " + type.getName() + " name " + name + " on " + c.getName() + " and " + clazz.getName());
        }
    }

到这个扩展类就加载完成

返回下面这个方法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);
        }
    }
  • injectExtension 依赖注入
private T injectExtension(T instance) {
        try {
            //如果objectFactory不可能为空,见下面,构造方法里已经初始化过了
            if (objectFactory != null) {
                //遍历实例所有的方法
                for (Method method : instance.getClass().getMethods()) {
                    //判断是否是set方法 如果是setter方法
                    if (isSetter(method)) {
                        /**
                         * 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 {
                            //取setter方法属性
                            String property = getSetterProperty(method);
                            //根据第一个参数和类型 从List<ExtensionFactory>中获取实例
                            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;
    }

在上面代码中,objectFactory 变量的类型为 AdaptiveExtensionFactory,AdaptiveExtensionFactory 内部维护了一个 ExtensionFactory 列表,用于存储其他类型的 ExtensionFactory。Dubbo 目前提供了两种 ExtensionFactory,分别是 SpiExtensionFactory 和 SpringExtensionFactory。前者用于创建自适应的拓展,后者是用于从 Spring 的 IOC 容器中获取所需的拓展

Dubbo IOC 目前仅支持 setter 方式注入

  • private final ExtensionFactory objectFactory;`

因为再调用ExtensionLoader.getExtensionLoader(Color.class);方法的时候, dubbo已经对扩展类IOC进行初始化了

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


  • ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension());
    public T getAdaptiveExtension() {
        Object instance = cachedAdaptiveInstance.get();
        if (instance == null) {
            if (createAdaptiveInstanceError == null) {
                synchronized (cachedAdaptiveInstance) {
                    instance = cachedAdaptiveInstance.get();
                    if (instance == null) {
                        try {
                            //核心方法
                            instance = createAdaptiveExtension();
                            cachedAdaptiveInstance.set(instance);
                        } catch (Throwable t) {
                            createAdaptiveInstanceError = t;
                            throw new IllegalStateException("Failed to create adaptive instance: " + t.toString(), t);
                        }
                    }
                }
            } else {
                throw new IllegalStateException("Failed to create adaptive instance: " + createAdaptiveInstanceError.toString(), createAdaptiveInstanceError);
            }
        }

        return (T) instance;
    }
  • createAdaptiveExtension
  @SuppressWarnings("unchecked")
    private T createAdaptiveExtension() {
        try {
            //class org.apache.dubbo.common.extension.factory.AdaptiveExtensionFactory这个类的实现
            return injectExtension((T) getAdaptiveExtensionClass().newInstance());
        } catch (Exception e) {
            throw new IllegalStateException("Can't create adaptive extension " + type + ", cause: " + e.getMessage(), e);
        }
    }
  • getAdaptiveExtensionClass
   private Class<?> getAdaptiveExtensionClass() {
       //又是加载所有的扩展类
        getExtensionClasses();
        if (cachedAdaptiveClass != null) {
            return cachedAdaptiveClass;
        }
        return cachedAdaptiveClass = createAdaptiveExtensionClass();
    }
  • getExtensionClasses和上面的流程一样
   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() {
        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;
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值