一、Java SPI使用
1 2 3 4 5 6
| ServiceLoader<MySpiInterface> load = ServiceLoader.load(MySpiInterface.class); Iterator<MySpiInterface> iterator = load.iterator(); while (iterator.hasNext()) { MySpiInterface obj = iterator.next(); obj.doSomethind(); }
|
二、Java 惰性加载
java.util.ServiceLoader
里使用了惰性迭代器:java.util.ServiceLoader.LazyIterator
。
- 其会在首次调用
LazyIterator#hasNext
时,读取所有的META-INF下指定接口的文件名称,然后赋值给Enumeration<URL>
类型变量。
- 其内部还有一个迭代器pending,用以迭代单个SPI文件下定义的多个实现类。
- 其会在调用
LazyIterator#next
时,取出迭代器pending指向的SPI类,并进行初始化操作。
下面为其源码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92
| 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 { 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()); } nextName = pending.next(); return true; }
private S nextService() { 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"); } 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(); }
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(); }
}
|