java的spi(Service Provider Interface)机制及源码(java8)
1.什么是java的spi
spi 全称为 service provider interface 即 服务提供接口,用来作为服务的扩展发现。在运行时动态添加接口的实现,是对接口的实现类的创建管理。
2.运用场景
类似于spring dubbo都有基于java自带的spi模式实现的自有spi管理的机制。
3.如何使用
-
java 自带的spi
核心类是:java.util.ServiceLoader 该类是一个被final修饰的类
使用:
1.在jar包的"src/META-INF/services"目录下建立一个文件,该文件的文件名是对应接口的全限定名,文件的内容可以有多行,每行是该接口对应的具体实现类的全限定名。
private static final String PREFIX = "META-INF/services/";
2.在代码中使用java.util.ServiceLoader加载对应的接口类
//指定类加载器 public static <S> ServiceLoader<S> load(Class<S> service, ClassLoader loader) { return new ServiceLoader<>(service, loader); } //使用当前线程的类加载器 public static <S> ServiceLoader<S> load(Class<S> service) { ClassLoader cl = Thread.currentThread().getContextClassLoader(); return ServiceLoader.load(service, cl); } //使用extension class loader public static <S> ServiceLoader<S> loadInstalled(Class<S> service) { ClassLoader cl = ClassLoader.getSystemClassLoader(); ClassLoader prev = null; while (cl != null) { prev = cl; cl = cl.getParent(); } return ServiceLoader.load(service, prev); }
3. 调用ServiceLoader.load()方法后会new 一个 ServiceLoader<>(Class service, loader);
private ServiceLoader(Class<S> svc, ClassLoader cl) { // 这里的service 是对应的接口 service = Objects.requireNonNull(svc, "Service interface cannot be null"); // 类加载器 loader = (cl == null) ? ClassLoader.getSystemClassLoader() : cl; //获取当前的AccessControlContext 默认为空 acc = (System.getSecurityManager() != null) ? AccessController.getContext() : null; reload(); }
这里的acc 是 java的安全管理器
// The access control context taken when the ServiceLoader is created private final AccessControlContext acc;
对应的System.getSecurityManager() 获取当前的安全SecurityManager
java.lang.System类中 private static volatile SecurityManager security = null; public static SecurityManager getSecurityManager() { return security; }
4.接着调用reload方法
public void reload() { providers.clear(); lookupIterator = new LazyIterator(service, loader); }
providers 同lookupInterator
// Cached providers, in instantiation order private LinkedHashMap<String,S> providers = new LinkedHashMap<>(); // The current lazy-lookup iterator private LazyIterator lookupIterator;
5.new 一个内部类 懒加载类LazyInterator
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(); // 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(); } }
6.使用迭代器Interator取出接口的实现对象
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; return lookupIterator.hasNext(); } public S next() { if (knownProviders.hasNext()) return knownProviders.next().getValue(); return lookupIterator.next(); } public void remove() { throw new UnsupportedOperationException(); } }; }