public boolean hasNext() { // acc = (System.getSecurityManager() != null) ? AccessController.getContext() : null; // ServiceLoader初始化没有设置过securityManager,所以acc是null,进入hasNextService() if (acc == null) { return hasNextService(); } else { PrivilegedAction<Boolean> action = new PrivilegedAction<Boolean>() { public Boolean run() { return hasNextService(); } }; return AccessController.doPrivileged(action, acc); } }5.hasNextService()分析
private boolean hasNextService() { if (nextName != null) { return true; } if (configs == null) { try { // 这里加载了META-INF/services下的文件 也就是含有两个实现类全限定名的文件 String fullName = PREFIX + service.getName(); if (loader == null) configs = ClassLoader.getSystemResources(fullName); else // 因为loader是不为null 的AppClassLoader configs = loader.getResources(fullName); } catch (IOException x) { fail(service, "Error locating configuration files", x); } } while ((pending == null) || !pending.hasNext()) { if (!configs.hasMoreElements()) { return false; } // 这里是将上面加载的文件中的两个实现类的文件 pending = parse(service, configs.nextElement()); } nextName = pending.next(); return true; }6.继续看到parse方法,这里最后返回的是含有两个全限定类名的Iterator,其实就是把services/下的文件内容给加载出来
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();}附带的说一下parseLine(service, u, r, lc, names),检查类名是否符合规范,符合的话添加到Iterator中,到这里var2 .hasNext()执行完毕,结果是加载了services下的文件内容
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(' ') >= 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 boolean hasNextService() { if (nextName != null) { return true; } if (configs == null) { try { 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); } } while ((pending == null) || !pending.hasNext()) { if (!configs.hasMoreElements()) { return false; } pending = parse(service, configs.nextElement()); } // 这里将下一个实现类的名字赋值给了LazyIterator的属性nextName nextName = pending.next(); return true; }7.接下来执行的是 NinjaService item = (NinjaService)var2.next()的next(方法),然后继续debug进去,这里我省略了一些方法的调用,只展示出有用的方法这个是ServiceLoader的内部类LazyIterator的nextService()方法.
private S nextService() { if (!hasNextService()) throw new NoSuchElementException(); String cn = nextName; nextName = null; Class<?> c = null; try { // 这里nextName在上面已经赋值过了 所以反射创建实例 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()); // 将类添加到ServiceLoader的providers属性中 然后返回 providers.put(cn, p); return p; } catch (Throwable x) { fail(service, "Provider " + cn + " could not be instantiated", x); } throw new Error(); // This cannot happen }8.到这里子类的实现类返回,分析就结束了.
总结:
1.了解了什么是SPI;
2.SPI和API的简单区别和联系;
推荐阅读
- 程序员常说的CDN是什么?
- 一文了解阿里云CDN HTTP2.0
- 五分钟了解CDN
- 万重山的扦插图解 万重山怎么繁殖
- 食品添加剂的作用是什么 食品防腐剂有哪些
- 一个百亿级日志系统是怎么设计出来的?
- java架构到底是做什么的,一段对话让你懂
- 冻肉如何解冻成新鲜肉一一 冻肉如何解冻成新鲜肉
- HTML、CSS、JavaScript、PHP、 MySQL 的学习顺序是什么?
- 梦见烫发染发是怎么回事 梦到烫发染发是什么意思