ServiceLoader整理

ServiceLoader整理

  • ServiceLoader简单使用
    Search search = null; ServiceLoader serviceLoader = ServiceLoader.load(Search.class); Iterator searchs = serviceLoader.iterator(); if (searchs.hasNext()) { search = searchs.next(); }

  • 源码分析

    • ServiceLoader.load
      • public static ServiceLoader load(Class service) {
        ClassLoader cl = Thread.currentThread().getContextClassLoader();
        return ServiceLoader.load(service, cl);
        }
        public static ServiceLoader load(Class service, ClassLoader loader)
        {
        return new ServiceLoader<>(service, loader);
        }
        private ServiceLoader(Class svc, ClassLoader cl) {
        service = svc;
        loader = cl;
        reload();
        }
        public void reload() {
        providers.clear();//private LinkedHashMap providers = new LinkedHashMap<>();
        lookupIterator = new LazyIterator(service, loader);
        }
        private class LazyIterator implements Iterator//这里叫lazy其实就是调用hasNext的时候才去加载
        {
        ...
        private LazyIterator(Class service, ClassLoader loader) {
        this.service = service;
        this.loader = loader;
        }
        ...
        }
    • iterator()
      • public Iterator iterator() {
          return new Iterator() {//返回匿名内部类
              Iterator> knownProviders = providers.entrySet().iterator();//目前这个linkedhashmap还是空的
              public boolean hasNext() {
                  if (knownProviders.hasNext())
                      return true;
                  return lookupIterator.hasNext();//knownProviders空时走这个
              }
              public S next() {
                  if (knownProviders.hasNext())
                      return knownProviders.next().getValue();
                  return lookupIterator.next();
              }
              public void remove() {
                  throw new UnsupportedOperationException();
              }
          };
        
        }
    • hasNext()
      • public boolean hasNext() {
        if (nextName != null) {//null 调用next后会置nextName为null,不调用next则nextName始终不为null
        return true;
        }
        if (configs == null) {//null
        try {
        String fullName = PREFIX + service.getName();
        if (loader == null)//null
        configs = ClassLoader.getSystemResources(fullName);
        else
        //这里加载资源: META-INF/services/packageName.className
        //Finds all the resources with the given name.
        //A resource is some data (images, audio, text, etc) that can be accessed by class code in a way that is independent of the location of the code.
        configs = loader.getResources(fullName);
        } catch (IOException x) {
        fail(service, "Error locating configuration files", x);
        }
        }
        while ((pending == null) || !pending.hasNext()) {//null
        if (!configs.hasMoreElements()) {
        return false;
        }
        pending = parse(service, configs.nextElement());//go here
        }
        nextName = pending.next();// Iterator pending
        return true;
        }
      • private Iterator parse(Class service, URL u)throws ServiceConfigurationError
        {
        InputStream in = null;
        BufferedReader r = null;
        ArrayList 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();
        }
    • next()
      • public S next() {
        if (!hasNext()) {
        throw new NoSuchElementException();
        }
        String cn = nextName;
        nextName = null;// *** 置nextName为null ***
        Class c = null;
        try {
        c = Class.forName(cn, false, loader);
        } catch (ClassNotFoundException x) {
        fail(service, "Provider " + cn + " not found");
        }
        if (!service.isAssignableFrom(c)) {
        fail(service, "Provider " + cn + " not a subtype");
        }
        try {
        S p = service.cast(c.newInstance());// Casts an object to the class or interface represented by this Class object
        providers.put(cn, p);// add cache 放入到knownProviders里面
        return p;
        } catch (Throwable x) {
        fail(service, "Provider " + cn + " could not be instantiated: " + x, x);
        }
        throw new Error();// This cannot happen
        }
    • 小结
      • hasNext和next必须搭配一起使用
        • hasNext获取nextName从一个Iterator的pending中
        • next则拿这个nextName去加载创建Class并创建对象返回
      • 首次从lookupIterator中获取,后面从knownProviders缓存里面获取
  • References

    • Java中的SPI(Service Provider Interface)介绍及示例
    • java中的SPI机制

你可能感兴趣的:(ServiceLoader整理)