类图SPI 全称 Service Provider Interface ,是一种服务发现机制。通过提供接口、预定义的加载器( Loader )以及约定俗称的配置(一般在 meta-INF 目录下),可以实现动态加载服务实现类。
通过类图可以分析出, ServiceLoader 实现了 Iterable 接口,提供了迭代的功能。
而 ServiceLoader 将迭代的实现委托给 LazyIterator 。
LazyIterator 提供了延时迭代的能力,当有需要的时候,才去加载。
在 Skywalking 模块中的使用 接口定义org.apache.skywalking.oap.server.library.module.ModuleDefine
package org.apache.skywalking.oap.server.library.module;
import java.lang.reflect.Field;
import java.util.Enumeration;
import java.util.Properties;
import java.util.ServiceLoader;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public abstract class ModuleDefine implements ModuleProviderHolder {
private static final Logger LOGGER = LoggerFactory.getLogger(ModuleDefine.class);
private ModuleProvider loadedProvider = null;
private final String name;
public ModuleDefine(String name) {
this.name = name;
}
public final String name() {
return name;
}
public abstract Class[] services();
void prepare(ModuleManager moduleManager, ApplicationConfiguration.ModuleConfiguration configuration,
ServiceLoader moduleProviderLoader) throws ProviderNotFoundException, ServiceNotProvidedException, ModuleConfigException, ModuleStartException {
// etc...
}
// etc...
@Override
public final ModuleProvider provider() throws DuplicateProviderException, ProviderNotFoundException {
if (loadedProvider == null) {
throw new ProviderNotFoundException("There is no module provider in " + this.name() + " module!");
}
return loadedProvider;
}
}
接口实现
org.apache.skywalking.oap.server.library.module.baseModuleA
package org.apache.skywalking.oap.server.library.module;
public class baseModuleA extends ModuleDefine {
public baseModuleA() {
super("baseA");
}
// 需要提供服务的接口
@Override
public Class extends Service>[] services() {
return new Class[] {
ServiceABusiness1.class,
ServiceABusiness2.class
};
}
public interface ServiceABusiness1 extends Service {
void print();
}
public interface ServiceABusiness2 extends Service {
}
}
meta-INF 定义
meta-INF/services/org.apache.skywalking.oap.server.library.module.ModuleDefine
org.apache.skywalking.oap.server.library.module.baseModuleA使用方式
org.apache.skywalking.oap.server.library.module.ModuleManager#init
public void init(ApplicationConfiguration applicationConfiguration) {
// SPI机制加载
ServiceLoaderModuleDefine> moduleServiceLoader = ServiceLoader.load(ModuleDefine.class);
// 迭代器获取
for (ModuleDefine module : moduleServiceLoader) {
// do something
// etc...
}
// etc...
}
源码解析
package java.util; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.net.URL; import java.security.AccessController; import java.security.AccessControlContext; import java.security.PrivilegedAction; import java.util.ArrayList; import java.util.Enumeration; import java.util.Iterator; import java.util.List; import java.util.NoSuchElementException; public final class ServiceLoaderimplements Iterable{ // 目录前缀 private static final String PREFIX = "meta-INF/services/"; // 需要被加载对象的Class对象 private final Classservice; // 类加载器 private final ClassLoader loader; // The access control context taken when the ServiceLoader is created private final AccessControlContext acc; // 加载对象缓存(按实例化顺序排序) private linkedHashMapproviders = new linkedHashMap<>(); // 当前使用的懒加载迭代器 private LazyIterator lookupIterator; // 重载 public void reload() { // 清除加载对象缓存 providers.clear(); // 重置懒加载迭代器 lookupIterator = new LazyIterator(service, loader); } // 不允许直接创建ServiceLoader对象,只能通过loadXXX获取ServiceLoader对象 private ServiceLoader(Class svc, ClassLoader cl) { service = Objects.requireNonNull(svc, "Service interface cannot be null"); loader = (cl == null) ? ClassLoader.getSystemClassLoader() : cl; acc = (System.getSecurityManager() != null) ? AccessController.getContext() : null; reload(); } private static void fail(Class> service, String msg, Throwable cause) throws ServiceConfigurationError { throw new ServiceConfigurationError(service.getName() + ": " + msg, cause); } private static void fail(Class> service, String msg) throws ServiceConfigurationError { throw new ServiceConfigurationError(service.getName() + ": " + msg); } private static void fail(Class> service, URL u, int line, String msg) throws ServiceConfigurationError { fail(service, u + ":" + line + ": " + msg); } // 解析配置文件中的一行,如果没有注释,则加入到类名列表中 private int parseLine(Class> service, URL u, BufferedReader r, int lc, Listnames) 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('t') >= 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 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(); } // 懒加载迭代器,提供了延时迭代的能力,当有需要的时候,才去加载 private class LazyIterator implements Iterator { // 需要被加载对象的Class对象 Classservice; // 类加载器 ClassLoader loader; // 配置文件列表 Enumerationconfigs = null; // 当前迭代的配置文件中类名列表的迭代器 Iterator pending = null; // 下一个实现类名 String nextName = null; private LazyIterator(Class service, ClassLoader loader) { this.service = service; this.loader = loader; } // 是否有下一个Service 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; } // 获取下一个Service private S nextService() { if (!hasNextService()) throw new NoSuchElementException(); String cn = nextName; nextName = null; Class> c = null; try { // 类名 -> 类的Class对象 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 { // 授权资源 PrivilegedActionaction = new PrivilegedAction () { public Boolean run() { return hasNextService(); } }; return AccessController.doPrivileged(action, acc); } } // 迭代器,获取下个元素 public S next() { if (acc == null) { return nextService(); } else { // 授权资源 PrivilegedAction action = new PrivilegedAction() { public S run() { return nextService(); } }; return AccessController.doPrivileged(action, acc); } } // 不支持删除 public void remove() { throw new UnsupportedOperationException(); } } // 迭代器实现,如果有缓存从缓存中获取,没有则从懒加载迭代器加载 public Iteratoriterator() { return new Iterator() { Iterator> 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(); } }; } // 通过类的Class对象及类加载,获取ServiceLoader public static ServiceLoaderload(Classservice, ClassLoader loader) { return new ServiceLoader<>(service, loader); } // 通过类的Class对象,获取ServiceLoader public staticServiceLoaderload(Classservice) { ClassLoader cl = Thread.currentThread().getContextClassLoader(); return ServiceLoader.load(service, cl); } // 通过类的Class对象和扩展类加载器,获取ServiceLoader public staticServiceLoaderloadInstalled(Classservice) { ClassLoader cl = ClassLoader.getSystemClassLoader(); ClassLoader prev = null; while (cl != null) { prev = cl; cl = cl.getParent(); } return ServiceLoader.load(service, prev); } public String toString() { return "java.util.ServiceLoader[" + service.getName() + "]"; } }
PS: JDK 提供的 SPI 机制,必须要使用迭代器遍历获取需要的实现,而 Dubbo SPI 可以通过 #getExtension 获取指定实现类。
总结通过源码分析,可以了解到 Skywalking 没有定义自己的 SPI 机制,但深入阅读 Skywalking 的使用场景后,发现用 JDK 提供的 SPI 机制也没什么问题。
个人认为,任何技术都应该根据场景选取,适合的才是最好的,如果没有那么复杂的需要,没必要像 dubbo 一样,定义自己的 SPI 机制。
参考文档- Java Service Provider Interface
- Dubbo SPI



