java SPI
介绍
- Server Provider Interface,服务发现机制。将接口实现类的全限定名配置在文件中,并由服务加载读取配置文件,加载实现类。
- java 通过 ServiceLoader 类实现,定义在目录 META-INF/services 文件夹,在里面定义具体的实现类。通过反射获取实例。
- 破坏了双亲委派机制,参考:双亲委派机制
源码解析
总结
- 根据接口名调用 ServerLoader.load(), 根据约定找到 META-INF/services 目录,解析文件得到实现类的全限定名,然后循环 通过反射方法Class.forName()加载类,和通过newInstance() 将类实例化,并将实例化的类缓存到List对象,然后返回。
ServerLoader.load()
- 先寻找当前线程绑定的ClassLoader,如果没有就是使用SystemClassLoader
- 然后清除缓存,创建一个LazyIterator
public static <S> ServiceLoader<S> load(Class<S> service) {
// 获取当前线程的ClassLoader
ClassLoader cl = Thread.currentThread().getContextClassLoader();
return ServiceLoader.load(service, cl);
}
private ServiceLoader(Class<S> svc, ClassLoader cl) {
service = Objects.requireNonNull(svc, "Service interface cannot be null");
// 如果没有则使用SystemClassLoader
loader = (cl == null) ? ClassLoader.getSystemClassLoader() : cl;
acc = (System.getSecurityManager() != null) ? AccessController.getContext() : null;
reload();
}
public void reload() {
// 清空缓存、再创建一个LazyIterator
providers.clear();
lookupIterator = new LazyIterator(service, loader);
}
hasNext()、next()
- 调用hasNext()来做实例循环
- 调用next() 得到一个实例
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);
}
}
hasNextService()
- 获取文件的位置,加载配置文件
- 按行遍历文件内容,解析内容,赋给nextName集合
Iterator<String> pending = null;
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;
}
nextService()
- 通过解析到的全限定名加载类,并且创建实例放入缓存中,之后返回实例
private S nextService() {
if (!hasNextService())
throw new NoSuchElementException();
// 获取当前解析到的实现类全限定名
String cn = nextName;
nextName = null;
Class<?> c = null;
try {
// 加载指定的实现类
c = Class.forName(cn, false, loader);
}
···················
try {
// 创建实现类
S p = service.cast(c.newInstance());
// 缓存实现类
providers.put(cn, p);
return p;
}
················
}
缺陷
- 不能按需加载,需要遍历所有的实现,并实例化,然后在循环中才能找到我们需要的实现。如果不想用某些实现类,或者某些类实例化很耗时,它也被载入并实例化了,这就造成了浪费。
- 配置文件中只是简单的列出了所有的拓展实现,而没有给他们命名,导致获取某个实现类的方式不够灵活,只能通过循环的形式获取,不能根据某个参数来获取对应的实现类。
- 扩展之间彼此存在依赖,做不到自动注入和装配,不提供上下文的IOC和AOP功能。
- 扩展很难和其他的容器框架集成,比如扩展依赖一个外部Spring容器中的bean,原生的JDK SPI并不支持。
- 多个并发多线程使用 ServiceLoader 类的实例是不安全的。
Spring SPI
- 感觉大致与java相同,只不过换了方法(SpringFactoriesLoader.loadFactories)
- 可以拓展SpringBoot的自动装配
Dubbo SPI
- 可以按需加载,通过名字去文件里面找到对应的实现类全限定名然后加载实例化
- 支持 AOP、IOC (URL、@SPI、@Adaptive)
- 自适应扩展机制
总结
- 调用 ExtensionLoader.getExtensionLoader() 获取接口对应的拓展点加载器,先从缓存中获取,如果没有就通过构造函数创建
- 调用 extensionLoader.getExtension() 获取对应实现类的实例,先从缓存中获取,如果没有就通过 双重检测 的方式调用 createExtension() 创建实例
- 通过getExtensionClasses(),先从缓存中获取实现类,如果没有则加载目录下所有的扩展点实现类,再通过ClassLoader加载并放入缓存中,根据name获取到对应的扩展点实现类;通过 loadClass() 实现缓存操作,分别有 Adptive 拓展点放入、extensionClasses 普通实现类放入、cachedWrapperClasses AOP类放入。
- 通过 injectExtension(instance),IOC,依赖注入只能通过set方法注入,并获取依赖类的类型、名字,通过objectFactory.getExtension() 来创建依赖对象,执行注入依赖;
- 通过 WrapperClasses,AOP,通过 getExtensionClasses() 读取到的 AOP 代理类,存放在cachedWrapperClasses中,通过获取代理实例进行依赖注入。
源码解析
- 通过 ExtensionLoader.getExtensionLoader() 获取接口对应的拓展点加载器
- 通过 extensionLoader.getExtension() 获取对应实现类的实例
ExtensionLoader.getExtensionLoader()
- 从缓存中获取接口对应的拓展点加载器,如果没有就会通过构造函数创建,并且放到一个ConcurrentHashMap缓存中;
- 从缓存中获取:EXTENSION_LOADERS.get(type);
- 通过构造函数创建并存入缓存中:EXTENSION_LOADERS.putIfAbsent(type, new ExtensionLoader(type));
public static <T> ExtensionLoader<T> getExtensionLoader(Class<T> type) {
// 判断传入的类是否为空、接口、被@SPI注解修饰
if (type == null)
throw new IllegalArgumentException("Extension type == null");
if (!type.isInterface()) {
throw new IllegalArgumentException("Extension type(" + type + ") is not interface!");
}
if (!withExtensionAnnotation(type)) {
throw new IllegalArgumentException("Extension type(" + type +
") is not extension, because WITHOUT @" + SPI.class.getSimpleName() + " Annotation!");
}
// 从缓存中获取扩展点加载器、如果没有创建对应的加载器并返回
ExtensionLoader<T> loader = (ExtensionLoader<T>) EXTENSION_LOADERS.get(type);
if (loader == null) {
EXTENSION_LOADERS.putIfAbsent(type, new ExtensionLoader<T>(type));
loader = (ExtensionLoader<T>) EXTENSION_LOADERS.get(type);
}
return loader;
}
new ExtensionLoader(type)
private ExtensionLoader(Class<?> type) {
this.type = type;
objectFactory = (type == ExtensionFactory.class ? null : ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension());
}
extensionLoader.getExtension()
- 通过缓存获取目标实现类的实例,如果没有,会通过双重检查的方式调用 createExtension() 方法创建实例
- final域指令重排
- 单例模式
private final ConcurrentMap<String, Holder<Object>> cachedInstances = new ConcurrentHashMap<String, Holder<Object>>();
public T getExtension(String name) {
if (name == null || name.length() == 0)
throw new IllegalArgumentException("Extension name == null");
// 获取默认的实体类名字,@SPI注解里面的value属性就是默认
if ("true".equals(name)) {
return getDefaultExtension();
}
// 从缓存中获取持有目标对象,没有则创建
Holder<Object> holder = cachedInstances.get(name);
if (holder == null) {
cachedInstances.putIfAbsent(name, new Holder<Object>());
holder = cachedInstances.get(name);
}
// 单例模式、DCL双重检测
Object instance = holder.get();
if (instance == null) {
synchronized (holder) {
instance = holder.get();
if (instance == null) {
// 实例对象
instance = createExtension(name);
holder.set(instance);
}
}
}
return (T) instance;
}
createExtension()
- 通过 getExtensionClasses() 获取对应的实现类
- 从缓存中获取实例,如果没有通过反射创建实例
- 调用 injectExtension() 实现 setter 依赖注入
- wrapperClasses 包装类实现 AOP
private T createExtension(String name) {
// 获取扩展点对应的类(通过读取文件里面所有的实现类名字,用ClassLoader加载具体的实现类)
Class<?> clazz = getExtensionClasses().get(name);
if (clazz == null) {
throw findException(name);
}
try {
// 从缓存中获取实例,如果没有通过反射创建实例
T instance = (T) EXTENSION_INSTANCES.get(clazz);
if (instance == null) {
EXTENSION_INSTANCES.putIfAbsent(clazz, clazz.newInstance());
instance = (T) EXTENSION_INSTANCES.get(clazz);
}
// setter 依赖注入 IOC
injectExtension(instance);
// AOP
Set<Class<?>> wrapperClasses = cachedWrapperClasses;
if (wrapperClasses != null && !wrapperClasses.isEmpty()) {
for (Class<?> wrapperClass : wrapperClasses) {
instance = injectExtension((T) wrapperClass.getConstructor(type).newInstance(instance));
}
}
return instance;
}
·················
getExtensionClasses()
- 先从缓存中获取实现类,如果没有调用 loadExtensionClasses() 创建并存放到缓存中
private Map<String, Class<?>> getExtensionClasses() {
Map<String, Class<?>> classes = cachedClasses.get();
if (classes == null) {
synchronized (cachedClasses) {
classes = cachedClasses.get();
if (classes == null) {
classes = loadExtensionClasses();
cachedClasses.set(classes);
}
}
}
return classes;
}
private Map<String, Class<?>> loadExtensionClasses() {
final SPI defaultAnnotation = type.getAnnotation(SPI.class);
·············
Map<String, Class<?>> extensionClasses = new HashMap<String, Class<?>>();
// 从三个目录里面查找
// META-INF/services、META-INF/dubbo、META-INF/dubbo/internal
loadDirectory(extensionClasses, DUBBO_INTERNAL_DIRECTORY);
loadDirectory(extensionClasses, DUBBO_DIRECTORY);
loadDirectory(extensionClasses, SERVICES_DIRECTORY);
return extensionClasses;
}
loadDirectory()
- 根据类名和指定的目录,找到文件获取所有资源,然后一个一个去加载类
- 再通过 loadClass() 做三种缓存操作,缓存 Adaptive 、WrapperClass 和普通类这三种
private void loadDirectory(Map<String, Class<?>> extensionClasses, String dir) {
// 获取目录
String fileName = dir + type.getName();
try {
// 通过目录获取资源
Enumeration<java.net.URL> urls;
ClassLoader classLoader = findClassLoader();
if (classLoader != null) {
urls = classLoader.getResources(fileName);
} else {
urls = ClassLoader.getSystemResources(fileName);
}
// 遍历资源,调用loadResource一个一个加载
if (urls != null) {
while (urls.hasMoreElements()) {
java.net.URL resourceURL = urls.nextElement();
loadResource(extensionClasses, classLoader, resourceURL);
}
}
}
······················
}
private void loadClass(Map<String, Class<?>> extensionClasses, java.net.URL resourceURL, Class<?> clazz, String name) throws NoSuchMethodException {
·····························
// 如果类标注了 Adptive注解,保存
if (clazz.isAnnotationPresent(Adaptive.class)) {
if (cachedAdaptiveClass == null) {
cachedAdaptiveClass = clazz;
} else if (!cachedAdaptiveClass.equals(clazz)) {
throw ···············
}
// 如果是包装类注解, 保存
} else if (isWrapperClass(clazz)) {
Set<Class<?>> wrappers = cachedWrapperClasses;
if (wrappers == null) {
cachedWrapperClasses = new ConcurrentHashSet<Class<?>>();
wrappers = cachedWrapperClasses;
}
wrappers.add(clazz);
} else {
// 普通类进入
clazz.getConstructor();
······················
String[] names = NAME_SEPARATOR.split(name);
if (names != null && names.length > 0) {
Activate activate = clazz.getAnnotation(Activate.class);
if (activate != null) {
// 标记Adptive 注解,保存
cachedActivates.put(names[0], activate);
}
for (String n : names) {
if (!cachedNames.containsKey(clazz)) {
// 记录映射(类 --> 名字)
cachedNames.put(clazz, n);
}
Class<?> c = extensionClasses.get(n);
if (c == null) {
// 记录映射(名字 --> 类)
extensionClasses.put(n, clazz);
}
··························
}
}
}
}
injectExtension() IOC
- 依赖注入只能通过set方法注入,并获取依赖类的类型、名字
- 通过 objectFactory.getExtension() 获取依赖对象
- 通过 method.invoke() 执行set方法注入依赖
private T injectExtension(T instance) {
try {
if (objectFactory != null) {
for (Method method : instance.getClass().getMethods()) {
// 说明只能是set注入 并且方法仅有一个参数,且方法访问级别为 public
if (method.getName().startsWith("set")
&& method.getParameterTypes().length == 1
&& Modifier.isPublic(method.getModifiers())) {
Class<?> pt = method.getParameterTypes()[0];
try {
String property = method.getName().length() > 3 ? method.getName().substring(3, 4).toLowerCase() + method.getName().substring(4) : "";
// 将获取到的依赖的类,重新执行一遍流程getExtensionLoader()、getAdaptiveExtension()
Object object = objectFactory.getExtension(pt, property);
if (object != null) {
method.invoke(instance, object);
}
}
······························
return instance;
}
wrapperClasses AOP
- 通过 getExtensionClasses() 读取到的 AOP 代理类,存放在cachedWrapperClasses中
- 获取代理实例进行依赖注入
// cachedWrapperClasses是getExtensionClasses读取到的AOP代理类,存放在cachedWrapperClasses中
Set<Class<?>> wrapperClasses = cachedWrapperClasses;
if (wrapperClasses != null && !wrapperClasses.isEmpty()) {
for (Class<?> wrapperClass : wrapperClasses) {
// 获取代理类的实例,并进行依赖注入
instance = injectExtension((T) wrapperClass.getConstructor(type).newInstance(instance));
}
}
return instance;
参考