目录
基于【JDK1.8】
一、SPI简介
1、概念
SPI即service-provider-interface
的简写;
JDK内置的服务提供加载机制,可以为服务接口加载实现类,解耦是其核心思想,也是很多框架和组件的常用手段;
2、入门案例
2.1 定义接口
就是普通的接口,在SPI的机制中称为【service】,即服务;
public interface Animal {
String animalName () ;
}
2.2 两个实现类
提供两个模拟用来测试,就是普通的接口实现类,在SPI的机制中称为【service-provider】即服务提供方;
CatAnimal
实现类;
public class CatAnimal implements Animal {
@Override
public String animalName() {
System.out.println("Cat-Animal:布偶猫");
return "Ragdoll";
}
}
DogAnimal
实现类;
public class DogAnimal implements Animal {
@Override
public String animalName() {
System.out.println("Dog-Animal:哈士奇");
return "husky";
}
}
2.3 配置文件
文件目录:在代码工程中创建META-INF.services
文件夹;
文件命名:butte.program.basics.spi.inf.Animal
,即全限定接口名称;
文件内容:添加相应实现类的全限定命名;
butte.program.basics.spi.impl.CatAnimal
butte.program.basics.spi.impl.DogAnimal
2.4 测试代码
通过ServiceLoader
加载配置文件中指定的服务实现类,然后遍历并调用Animal
接口方法,从而执行不同服务提供方的具体逻辑;
public class SpiAnaly {
public static void main(String[] args) {
ServiceLoader<Animal> serviceLoader = ServiceLoader.load(Animal.class);
Iterator<Animal> animalIterator = serviceLoader.iterator();
while(animalIterator.hasNext()) {
Animal animal = animalIterator.next();
System.out.println("animal-name:" + animal.animalName());
}
}
}
结果输出
Cat-Animal:布偶猫 \n animal-name:ragdoll
Dog-Animal:哈士奇 \n animal-name:husky
二、原理分析
1、ServiceLoader结构
很显然,分析SPI机制的原理,从ServiceLoader
源码中load
方法切入即可,但是需要先从核心类的结构开始分析;
public final class ServiceLoader<S> implements Iterable<S> {
// 配置文件目录
private static final String PREFIX = "META-INF/services/";
// 表示正在加载的服务的类或接口
private final Class<S> service;
// 类加载器用来定位,加载,实例化服务提供方
private final ClassLoader loader;
// 创建ServiceLoader时采用的访问控制上下文
private final AccessControlContext acc;
// 按实例化的顺序缓存服务提供方
private LinkedHashMap<String,S> providers = new LinkedHashMap<>();
// 惰性查找迭代器
private LazyIterator lookupIterator;
/**
* service:表示服务的接口或抽象类
* loader: 类加载器
*/
public static <S> ServiceLoader<S> load(Class<S> service) {
ClassLoader cl = Thread.currentThread().getContextClassLoader();
return ServiceLoader.load(service, cl);
}
/**
* ServiceLoader构造方法
*/
private ServiceLoader(Class<S> svc, ClassLoader cl) {
loader = (cl == null) ? ClassLoader.getSystemClassLoader() : cl;
acc = (System.getSecurityManager() != null) ? AccessController.getContext() : null;
reload();
}
public void reload() {
providers.clear();
// 实例化迭代器
lookupIterator = new LazyIterator(service, loader);
}
public static <S> ServiceLoader<S> load(Class<S> service,ClassLoader loader) {
return new ServiceLoader<>(service, loader);
}
private class LazyIterator implements Iterator<S> {
// 服务接口
Class<S> service;
// 类加载器
ClassLoader loader;
// 实现类URL
Enumeration<URL> configs = null;
// 实现类全名
Iterator<String> pending = null;
// 下个实现类全名
String nextName = null;
}
}
断点截图:
2、iterator迭代方法
在ServiceLoader
类的迭代器方法中,实际使用的是LazyIterator
内部类的方法;
p