dubbo源码系列1——spi源码解读(上)

        Dubbo作为分布式服务框架,致力于提供高性能和透明化的RPC远程服务调用方案。以微内核+插件机制作为底座,为上层提供易拓展特性,微内核和插件的核心即spi机制。介绍spi肯定离不开sdk提供的spi,因此分成上下两节分别介绍sdk spi和dubbo spi。本节主要有四部分,安排如下:

  1. spi介绍
  2. jdk spi demo
  3. jdk spi源码分析
  4. 总结

1、spi介绍

         spi(Service provider interface,服务发现机制)通俗的讲即接口制定者制定规范, 实现接口的提供者按这种规范去指定接口的实现类(通过在META-INF/services下创建文件名为接口名的文件,在文件中指定当前接口的实现类),运行时调用方到指定地方读取配置得到当前接口的实现类,无需通过硬编码的方式在代码中指定接口的实现类,从而实现解耦。

2、jdk spi demo

  • 接口
package xu.jiang.hua.jdk.service;
public interface IService {
     
    public void doSomeThing(String name);
}
  • 服务实现
package xu.jiang.hua.jdk.service.impl;
import xu.jiang.hua.jdk.service.IService;
public class WriteService implements IService {
     
    @Override
    public void doSomeThing(String name) {
     
        System.out.println("写服务:"+name);
    }
}

package xu.jiang.hua.jdk.service.impl;
import xu.jiang.hua.jdk.service.IService;
public class ReadService implements IService {
     
    @Override
    public void doSomeThing(String name) {
     
        System.out.println("读服务:"+name);
    }
}
package xu.jiang.hua.jdk;

import xu.jiang.hua.jdk.service.IService;

import java.util.Iterator;
import java.util.ServiceLoader;

public class TestMain {
     

    public static void main(String[] args) {
     

        ServiceLoader<IService> service = ServiceLoader.load(IService.class);

        Iterator<IService> it = service.iterator();

        while (it.hasNext()){
     
            IService s = it.next();
            s.doSomeThing("zzz");
        }
    }
}

  • 配置

dubbo源码系列1——spi源码解读(上)_第1张图片

  • 运行结果
    dubbo源码系列1——spi源码解读(上)_第2张图片
            ServiceLoader到/META-INF/services下根据接口名(xu.jiang.hua.jdk.service.IService)找到文件,然后加载文件读取内容,从而得到 IService的实现类。

3、 jdk spi源码分析

        因核心类为ServceiLoader,代码量不大,则整体贴出来。如下所示:

public final class ServiceLoader<S>
        implements Iterable<S>
{
     

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

    // The class or interface representing the service being loaded
    private final Class<S> service;

    // The class loader used to locate, load, and instantiate providers
    private final ClassLoader loader;

    // The access control context taken when the ServiceLoader is created
    private final AccessControlContext acc;

    // Cached providers, in instantiation order
    private LinkedHashMap<String,S> providers = new LinkedHashMap<>();

    // The current lazy-lookup iterator
    private java.util.ServiceLoader.LazyIterator lookupIterator;

    public void reload() {
     
        //
        providers.clear();
        //将初始化查找迭代器
        lookupIterator = new LazyIterator(service, loader);
    }

    private ServiceLoader(Class<S> svc, ClassLoader cl) {
     
        service = Objects.requireNonNull(svc, "Service interface cannot be null");
        loader = (cl == null) ? ClassLoader.getSystemClassLoader() : cl;
        acc = (System.getSecurityManager() != null) ? AccessController.getContext() : null;
        //加载
        reload();
    }

    private static void fail(Class<?> service, String msg, Throwable cause)
            throws ServiceConfigurationError
    {
     
        throw new ServiceConfigurationError(service.getName() + ": " + msg,
                cause);
    }

    private static void fail(Class<?> service, String msg)
            throws ServiceConfigurationError
    {
     
        throw new ServiceConfigurationError(service.getName() + ": " + msg);
    }

    private static void fail(Class<?> service, URL u, int line, String msg)
            throws ServiceConfigurationError
    {
     
        fail(service, u + ":" + line + ": " + msg);
    }

    /**
     * 解析配置中的文件
     * @param service
     * @param u
     * @param r
     * @param lc
     * @param names
     * @return
     * @throws IOException
     * @throws ServiceConfigurationError
     */
    private int parseLine(Class<?> service, URL u, BufferedReader r, int lc,
                          List<String> names)
            throws IOException, ServiceConfigurationError
    {
     
        String ln = r.readLine();
        if (ln == null) {
     
            return -1;
        }
        int ci = ln.indexOf('#');
        if (ci >= 0) ln = ln.substring(0, ci);
        ln = ln.trim();
        int n = ln.length();
        if (n != 0) {
     
            if ((ln.indexOf(' ') >= 0) || (ln.indexOf('\t') >= 0))
                fail(service, u, lc, "Illegal configuration-file syntax");
            int cp = ln.codePointAt(0);
            if (!Character.isJavaIdentifierStart(cp))
                fail(service, u, lc, "Illegal provider-class name: " + ln);
            for (int i = Character.charCount(cp); i < n; i += Character.charCount(cp)) {
     
                cp = ln.codePointAt(i);
                if (!Character.isJavaIdentifierPart(cp) && (cp != '.'))
                    fail(service, u, lc, "Illegal provider-class name: " + ln);
            }
            //如果不存在,则将读取的类加入集合
            if (!providers.containsKey(ln) && !names.contains(ln))
                names.add(ln);
        }
        return lc + 1;
    }


    private Iterator<String> parse(Class<?> service, URL u)
            throws ServiceConfigurationError
    {
     
        InputStream in = null;
        BufferedReader r = null;
        ArrayList<String> names = new ArrayList<>();
        try {
     
            in = u.openStream();
            r = new BufferedReader(new InputStreamReader(in, "utf-8"));
            int lc = 1;
            //循环读取配置的类名,直到读完为止。
            while ((lc = parseLine(service, u, r, lc, names)) >= 0);
        } catch (IOException x) {
     
            fail(service, "Error reading configuration file", x);
        } finally {
     
            try {
     
                if (r != null) r.close();
                if (in != null) in.close();
            } catch (IOException y) {
     
                fail(service, "Error closing configuration file", y);
            }
        }
        return names.iterator();
    }

   //赖迭代器,用于遍历文件中的所有内容
    private class LazyIterator
            implements Iterator<S>
    {
     

        Class<S> service;
        ClassLoader loader;
        Enumeration<URL> configs = null;
        Iterator<String> pending = null;
        String nextName = null;

        private LazyIterator(Class<S> service, ClassLoader loader) {
     
            this.service = service;
            this.loader = loader;
        }

        private boolean hasNextService() {
     
            if (nextName != null) {
     
                return true;
            }
            if (configs == null) {
     
                try {
     
                    //META-SERVICE/services/+类名
                    String fullName = PREFIX + service.getName();
                    if (loader == null)
                        configs = ClassLoader.getSystemResources(fullName);
                    else
                         //通过类加载器加载文件
                        configs = loader.getResources(fullName);
                } catch (IOException x) {
     
                    fail(service, "Error locating configuration files", x);
                }
            }
            //首次进入时pengding为null会进入循环,以及pengding不存在下一个时也进入循环
            while ((pending == null) || !pending.hasNext()) {
     
               
                if (!configs.hasMoreElements()) {
     
                    return false;
                }
                //调用parse方法,parse会将配置里面的类全部解析出来存放在ArrayList里面,但只返回list的迭代器
                pending = parse(service, configs.nextElement());
            }
            //在判断是否存在下一个时,将取到的赋值给nextName,则在调用nextService时,直接用nextName
            nextName = pending.next();
            return true;
        }

        private S nextService() {
     

            /**
             * 执行nextService之前,其实已经通过hasNextService判断是否还要下一个service。
             * 如果存在,才会调用nextService.此处再次判断,如果为false,则抛出异常
             */
            if (!hasNextService())
                throw new NoSuchElementException();
            //
            String cn = nextName;
            nextName = null;
            Class<?> c = null;
            try {
     
                //加载类
                c = Class.forName(cn, false, loader);
            } catch (ClassNotFoundException x) {
     
                fail(service,
                        "Provider " + cn + " not found");
            }
            //判断c是否是servcie的实现类
            if (!service.isAssignableFrom(c)) {
     
                fail(service,
                        "Provider " + cn  + " not a subtype");
            }
            try {
     
                //实例化
                S p = service.cast(c.newInstance());
                providers.put(cn, p);
                return p;
            } catch (Throwable x) {
     
                fail(service,
                        "Provider " + cn + " could not be instantiated",
                        x);
            }
            throw new Error();          // This cannot happen
        }

        public boolean hasNext() {
     
            if (acc == null) {
     
                //
                return hasNextService();
            } else {
     
                PrivilegedAction<Boolean> action = new PrivilegedAction<Boolean>() {
     
                    public Boolean run() {
      return hasNextService(); }
                };
                return AccessController.doPrivileged(action, acc);
            }
        }

        public S next() {
     
            if (acc == null) {
     
                //
                return nextService();
            } else {
     
                PrivilegedAction<S> action = new PrivilegedAction<S>() {
     
                    public S run() {
      return nextService(); }
                };
                return AccessController.doPrivileged(action, acc);
            }
        }

        public void remove() {
     
            throw new UnsupportedOperationException();
        }

    }

    /**
     * @return  An iterator that lazily loads providers for this loader's
     *          service
     */
    public Iterator<S> iterator() {
     
        return new Iterator<S>() {
     

            Iterator<Map.Entry<String,S>> knownProviders
                    = providers.entrySet().iterator();

            public boolean hasNext() {
     
                if (knownProviders.hasNext())
                    return true;
                //调用懒迭代器的hasNext
                return lookupIterator.hasNext();
            }

            public S next() {
     
                if (knownProviders.hasNext())
                    return knownProviders.next().getValue();
                //调用懒迭代器的next
                return lookupIterator.next();
            }

            public void remove() {
     
                throw new UnsupportedOperationException();
            }

        };
    }


    public static <S> java.util.ServiceLoader<S> load(Class<S> service,
                                                      ClassLoader loader)
    {
     
        return new java.util.ServiceLoader<>(service, loader);
    }


    public static <S> java.util.ServiceLoader<S> load(Class<S> service) {
     
        ClassLoader cl = Thread.currentThread().getContextClassLoader();
        return java.util.ServiceLoader.load(service, cl);
    }


    public static <S> java.util.ServiceLoader<S> loadInstalled(Class<S> service) {
     
        ClassLoader cl = ClassLoader.getSystemClassLoader();
        ClassLoader prev = null;
        while (cl != null) {
     
            prev = cl;
            cl = cl.getParent();
        }
        return java.util.ServiceLoader.load(service, prev);
    }

    /**
     * Returns a string describing this service.
     *
     * @return  A descriptive string
     */
    public String toString() {
     
        return "java.util.ServiceLoader[" + service.getName() + "]";
    }

}

      下面根据demo进行debug看看具体执行流程,整体流程分成三部分:
      A、实例化ServiceLoader;
      B、执行hasNext判断是否还存在service;
      C、执行next得到service;

  • 实例化ServiceLoader
    在这里插入图片描述
    在这里插入图片描述

        可以看到lookupIterator = new LazyIterator(service, loader),此时并没有加载文件(延迟加载);

  • 执行hasNext判断是否还存在service

        因ServiceLoader实现Iterable接口,因此执行Iterator it = service.iterator()时返回ServiceLoader自身实现iterator,如下所示:dubbo源码系列1——spi源码解读(上)_第3张图片
        执行LazyIterator的hasNextService方法时,会执行pase方法加载文件内容并存储在list中,但只返回list的迭代器,如下所示:
dubbo源码系列1——spi源码解读(上)_第4张图片

  • 执行next得到service
    dubbo源码系列1——spi源码解读(上)_第5张图片
    执行 lookupIterator.next(),如下所示:
    dubbo源码系列1——spi源码解读(上)_第6张图片

调用nextService:
dubbo源码系列1——spi源码解读(上)_第7张图片
        在nextService中再次执行hasNextService检查是否还存在service。如果不存在,则抛出异常。如果存在则通过类加载器加载类并进行实例化,然后存入provider中并返回服务类的实例。

        调用迭代器的hasNext方法直到以下返回false跳出循环,完成所有接口实现类的实例化。
dubbo源码系列1——spi源码解读(上)_第8张图片
        返回list(里面保存的ServiceName)迭代器的pending已经遍历完,同时configs也不再有下一个元素,则返回false,则结束整个遍历。

4、总结

        通过demo深入分析 jdk spi加载机制,为后续学习理解dubbo spi打下基础。想一下,jdk的spi有没有什么缺陷与不足?预知后事如何,且听下回分解!

你可能感兴趣的:(dubbo,java,dubbo,spi)