首先看strategies 属性的定义:
private static volatile LoadingStrategy[] strategies = loadLoadingStrategies();
点进去看初始化方法:loadLoadingStrategies()
private static LoadingStrategy[] loadLoadingStrategies() {
return java.util.stream.StreamSupport.stream(java.util.ServiceLoader.load(LoadingStrategy.class).spliterator(), false)
.sorted()
.toArray(LoadingStrategy[]::new);
}
加载过程解析
ServiceLoader.load方法,利用的是jdk自带的spi机制,加载 LoadingStrategy类的实现类,
jdk的spi机制约定了,接口实现类的描述文件存放位置为:META-INFO/services/,文件名称为接口的全限定名,即 org.apache.dubbo.common.extension.LoadingStrategy
,文件内容如下:
org.apache.dubbo.common.extension.DubboInternalLoadingStrategy
org.apache.dubbo.common.extension.DubboLoadingStrategy
org.apache.dubbo.common.extension.ServicesLoadingStrategy
显然,LoadingStrategy接口有三种实现,因此,jdk的spi机制,会将这三个实现分别初始化,并以数组的方式填充到 strategies
属性中,也就是说,不同的属性代表着不同的加载策略。
到这一步,strategies
属性就加载完成了。那么,strategies
字段在哪里使用呢?
我们再来看这一段代码:
private Map<String, Class<?>> loadExtensionClasses() {
cacheDefaultExtensionName();
Map<String, Class<?>> 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;
}
总结:strategies中的每一项,代表着不同的spi加载策略,每一种加载策略,都有相应的目录结构。因此dubbo通过遍历strategies,来读取某一个接口在所有策略下的所有实现类,并以k - v的方式缓存到extensionClasses
中,但是到这一步,还仅仅读取了实现类的class对象,而没有进行初始化。后续使用实现类时,可以直接拿到class对象,而不需要再去读取文件了。