java spi及原理 目录 目录 源码 lazy迭代器 dubbo的spi spi核心其实也很简单….spi全名即 源码12345678910111213141516171819202122public static <S> ServiceLoader<S> load(Class<S> service) { ClassLoader cl = Thread.currentThread().getContextClassLoader(); return ServiceLoader.load(service, cl);}// load的时候调用此构造器private ServiceLoader(Class<S> svc, ClassLoader cl) { // 传入的api service = Objects.requireNonNull(svc, "Service interface cannot be null"); // 类加载器 loader = (cl == null) ? ClassLoader.getSystemClassLoader() : cl; // acc = (System.getSecurityManager() != null) ? AccessController.getContext() : null; reload();}// public void reload() { // 清空缓存(provider是一个map) providers.clear(); lookupIterator = new LazyIterator(service, loader);} lazy迭代器12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758private 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; } ... 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); } } ... private S nextService() { if (!hasNextService()) throw new NoSuchElementException(); String cn = nextName; // 清空nextName 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()); // 放入缓存.. providers.put(cn, p); return p; } catch (Throwable x) { fail(service, "Provider " + cn + " could not be instantiated", x); } throw new Error(); // This cannot happen }} dubbo的spi