SPI 全称为 Service Provider Interface,是一种服务发现机制。当程序运行调用接口时,会根据配置文件或默认规则信息加载对应的实现类。所以在程序中并没有直接指定使用接口的哪个实现,而是在外部进行装配。
要想了解 Dubbo 的设计与实现,其中 Dubbo SPI 加载机制是必须了解的,在 Dubbo 中有大量功能的实现都是基于 Dubbo SPI 实现解耦,同时也使得 Dubbo 获得如此好的可扩展性。
通过完成一个 Java SPI 的操作来了解它的机制。
在pom文件中引入junit
junit
junit
4.13.2
public interface PersonService {
void hello();
}
public class ChinesePerson implements PersonService {
@Override
public void hello() {
System.out.println("我是中国人");
}
}
public class JavaSPITest {
@Test
public static void main(String[] args) {
ServiceLoader serviceLoader = ServiceLoader.load(PersonService.class);
// 遍历在配置文件中已配置的 AnimalService 的所有实现类
for (PersonService person : serviceLoader) {
person.hello();
}
}
}
我是中国人
Process finished with exit code 0
Dubbo SPI 相较于 Java SPI 更为强大,并且都是由自己实现的一套 SPI 机制。其中主要的改进和优化:
Dubbo SPI 的配置文件放在 META-INF/dubbo 下面,并且实现类的配置方式采用 K-V 的方式,key 为实例化对象传入的参数,value 为扩展点实现类全限定名。例如 ChinesePerson 的配置文件内容:
需要在接口上增加 @SPI 注解,@SPI 中可以指定 key 值
@SPI("chinesePerson")
public interface PersonService {
void hello();
}
public class ChinesePerson implements PersonService {
@Override
public void hello() {
System.out.println("我是中国人");
}
}
public class DubboSPITest {
@Test
public void spi() {
ExtensionLoader extensionLoader = ExtensionLoader.getExtensionLoader(PersonService.class);
// 获取扩展类实现
PersonService personService = extensionLoader.getExtension("chinesePerson");
personService.hello();
}
}
我是中国人
Process finished with exit code 0
ExtensionLoader 类在dubbo的dubbo-common模块中定义,获取 ExtensionLoader 实例是通过上面 getExtensionLoader 方法,具体实现代码:
@SuppressWarnings("unchecked")
public static ExtensionLoader getExtensionLoader(Class type) {
if (type == null) {
throw new IllegalArgumentException("Extension type == null");
}
// 检查type 必须为接口类型
if (!type.isInterface()) {
throw new IllegalArgumentException("Extension type (" + type + ") is not an interface!");
}
// 检查type 类型上是否有注解 SPI
if (!withExtensionAnnotation(type)) {
throw new IllegalArgumentException("Extension type (" + type +
") is not an extension, because it is NOT annotated with @" + SPI.class.getSimpleName() + "!");
}
// 从ConcurrentHashMap 中获取实例
ExtensionLoader loader = (ExtensionLoader) EXTENSION_LOADERS.get(type);
if (loader == null) {
// 创建ExtensionLoader实例,并放入缓存
EXTENSION_LOADERS.putIfAbsent(type, new ExtensionLoader(type));
loader = (ExtensionLoader) EXTENSION_LOADERS.get(type);
}
return loader;
}
上面获取扩展类加载器过程主要是检查传入的 type 是否合法,以及从扩展类加载器缓存中是否存在当前类型的接口,如果不存在则添加当前接口至缓存中。ConcurrentMap
是扩展类加载器的缓存,它是以接口作为 key, 扩展类加载器作为 value 进行缓存。
获取扩展类对象
获取扩展类对象的方法ExtensionLoader#getExtension
,在这里完成扩展对象的缓存及创建工作:
public T getExtension(String name, boolean wrap) {
if (StringUtils.isEmpty(name)) {
throw new IllegalArgumentException("Extension name == null");
}
//如果传入的参数为 true ,则获取默认扩展类对象操作
if ("true".equals(name)) {
return getDefaultExtension();
}
//获取扩展对象,Holder 里的 value 属性保存着扩展对象实例
final Holder
获取 holder 对象是从缓存ConcurrentMap
中获取,如果不存在,则以扩展名 key,创建一个 Holder 对象作为 value,设置到扩展对象缓存。
如果是新创建的扩展对象实例,那么 holder.get() 一定是 null ,扩展对象为空时,经过双重检查锁,创建扩展对象。
创建扩展对象过程
@SuppressWarnings("unchecked")
private T createExtension(String name, boolean wrap) {
// 从全部扩展类中,获取当前扩展名对应的扩展类
// 读取 META-INF/dubbo/external/
// META-INF/dubbo/internal/
// META-INF/services/
Class> clazz = getExtensionClasses().get(name);
if (clazz == null) {
throw findException(name);
}
try {
// 从缓存ConcurrentMap, Object>中获取扩展实例,及设置扩展实例缓存
T instance = (T) EXTENSION_INSTANCES.get(clazz);
if (instance == null) {
EXTENSION_INSTANCES.putIfAbsent(clazz, clazz.newInstance());
instance = (T) EXTENSION_INSTANCES.get(clazz);
}
// 向当前实例注入依赖
injectExtension(instance);
if (wrap) {
List> wrapperClassesList = new ArrayList<>();
if (cachedWrapperClasses != null) {
wrapperClassesList.addAll(cachedWrapperClasses);
wrapperClassesList.sort(WrapperComparator.COMPARATOR);
Collections.reverse(wrapperClassesList);
}
if (CollectionUtils.isNotEmpty(wrapperClassesList)) {
for (Class> wrapperClass : wrapperClassesList) {
Wrapper wrapper = wrapperClass.getAnnotation(Wrapper.class);
if (wrapper == null
|| (ArrayUtils.contains(wrapper.matches(), name) && !ArrayUtils.contains(wrapper.mismatches(), name))) {
// 创建包装扩展类实例,并向其注入依赖
instance = injectExtension((T) wrapperClass.getConstructor(type).newInstance(instance));
}
}
}
}
// 初始化扩展对象
initExtension(instance);
return instance;
} catch (Throwable t) {
throw new IllegalStateException("Extension instance (name: " + name + ", class: " +
type + ") couldn't be instantiated: " + t.getMessage(), t);
}
}
获取所有扩展类
private Map> getExtensionClasses() {
// 获取普通扩展类缓存
Map> classes = cachedClasses.get();
if (classes == null) {
// ➕锁
synchronized (cachedClasses) {
classes = cachedClasses.get();
if (classes == null) {
// 加载全部扩展类
classes = loadExtensionClasses();
cachedClasses.set(classes);
}
}
}
return classes;
}
loadExtensionClasses 加载全部扩展类
/**
* synchronized in getExtensionClasses
* 读取 META-INF/dubbo/external/
* META-INF/dubbo/internal/
* META-INF/services/
*/
private Map> loadExtensionClasses() {
cacheDefaultExtensionName();
Map> extensionClasses = new HashMap<>();
for (LoadingStrategy strategy : strategies) {
loadDirectory(extensionClasses, strategy.directory(), type.getName(), strategy.preferExtensionClassLoader(), strategy.overridden(), strategy.excludedPackages());
loadDirectory(extensionClasses, strategy.directory(), type.getName().replace("org.apache", "com.alibaba"), strategy.preferExtensionClassLoader(), strategy.overridden(), strategy.excludedPackages());
}
return extensionClasses;
}