上一篇博客中我们介绍了dubbo中SPI功能的使用规则,这里我们看一下它的加载过程:
这里它的加载过程就两步:
- 获取ExtensionLoader的实例对象
- 通过ExtensionLoader的实例对象获取到我们要的扩展点实例
1、获取ExtensionLoader实例对象
getExtensionLoader 方法做了这么几件事:
1、 判断class对象是否为空、是否为接口、类上是否有@SPI注解
2、查询缓存获取ExtensionLoader实例, 如果没有则创建一个实例对象,并放入缓存中
public static <T> ExtensionLoader<T> getExtensionLoader(Class<T> type) {
if (type == null)
throw new IllegalArgumentException("Extension type == null");
if (!type.isInterface()) {
throw new IllegalArgumentException("Extension type(" + type + ") is not interface!");
}
// 如果没有SPI注解,报错
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;
}
我们可以看一下它的构造方法:
private ExtensionLoader(Class<?> type) {
this.type = type;
/**
* type如果是ExtensionFactory类型,那么objectFactory是null,否则是ExtensionFactory类型的适配器类型
*/
objectFactory = (type == ExtensionFactory.class ? null : ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension());
}
私有构造,说明它无法在外部进行实例化; ExtensionFactory 是通过扩展点类型和名称来获取扩展点的。
@SPI
public interface ExtensionFactory {
/**
* Get extension.
*
* @param type object type.
* @param name object name.
* @return object instance.
*/
<T> T getExtension(Class<T> type, String name);
}
ExtensionFactory 的扩展点有三个:
2、获取扩展点实例:
getAdaptiveExtension方法获取扩展点实例, 它也是先从缓存中获取扩展点实例,如果没有则创建, 并放入缓存中:createAdaptiveExtension方法
public T getAdaptiveExtension() {
Object instance = cachedAdaptiveInstance.get();
if (instance == null) {
if (createAdaptiveInstanceError != null) {
throw new IllegalStateException("Failed to create adaptive instance: " +
createAdaptiveInstanceError.toString(),
createAdaptiveInstanceError);
}
synchronized (cachedAdaptiveInstance) {
instance = cachedAdaptiveInstance.get();
if (instance == null) {
try {
//缓存中获取不到就创建
instance = createAdaptiveExtension();
cachedAdaptiveInstance.set(instance);
} catch (Throwable t) {
createAdaptiveInstanceError = t;
throw new IllegalStateException("Failed to create adaptive instance: " + t.toString(), t);
}
}
}
}
return (T) instance;
}
1、createAdaptiveExtension: 调用getAdaptiveExtensionClass
- 获取到适配器类的Class。
- 利用反射创建适配器类的实例。
- injectExtension是dubbo的DI,依赖注入,如果适配器类有属性的set方法,会自动注入。
private T createAdaptiveExtension() {
try {
return injectExtension((T) getAdaptiveExtensionClass().newInstance());
} catch (Exception e) {
throw new IllegalStateException("Can not create adaptive extension " + type + ", cause: " + e.getMessage(), e);
}
}
2、getAdaptiveExtensionClass:
- SPI扫描: 包括@SPI、@Adaptive注解的类和方法、 SPI 配置文件(这一步是SPI的关键)
- 如果上一步获取到了cachedAdaptiveClass 则返回
- 创建cachedAdaptiveClass 动态代理类
private Class<?> getAdaptiveExtensionClass() {
/**
* 触发SPI流程的扫描
*/
getExtensionClasses();
/**
* 如果通过上面的步骤可以获取到cachedAdaptiveClass直接返回
*/
if (cachedAdaptiveClass != null) {
return cachedAdaptiveClass;
}
/**
* 利用动态代理创建一个扩展类
*/
return cachedAdaptiveClass = createAdaptiveExtensionClass();
}
2.1、 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;
}
2.1.1、 loadExtensionClasses 加载扩展点
它的主要职能有两个:
- 加载当前SPI默认实现
- 加载这个类的所有扩展点实现,且按照name和class对象的形式存储
/**
* synchronized in getExtensionClasses
*/
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;
}
2.1.1.1: cacheDefaultExtensionName 加载并缓存当前SPI默认实现
private void cacheDefaultExtensionName() {
// 获取当前类是够包含SPI注解, 一般走道这里就是拥有该注解
final SPI defaultAnnotation = type.getAnnotation(SPI.class);
if (defaultAnnotation == null) {
return;
}
// 获取SPI注解的value值
String value = defaultAnnotation.value();
if ((value = value.trim()).length() > 0) {
String[] names = NAME_SEPARATOR.split(value);
if (names.length > 1) {
throw new IllegalStateException("More than 1 default extension name on extension " + type.getName()
+ ": " + Arrays.toString(names));
}
if (names.length == 1) {
cachedDefaultName = names[0];
}
}
}
2.1.1.2:loadDirectory 加载扩展点实现
这里的主要工作是:
- 拼接文件名
- 先从缓存中尝试获取需要的扩展点
- 如果URL为空,即没有文件或文件中没有任何配置,尝试从其他线程获取扩展点
- 如果URL存在,逐个遍历文件资源,并加载资源信息到ExtensionClasses中
private void loadDirectory(Map<String, Class<?>> extensionClasses, String dir, String type,
boolean extensionLoaderClassLoaderFirst, boolean overridden, String... excludedPackages) {
// 拼接文件名: 路径/包名.接口名
String fileName = dir + type;
try {
// 寻找classloader和url列表
Enumeration<java.net.URL> urls = null;
ClassLoader classLoader = findClassLoader();
// 如果需要,先从当前类的ClassLoader中获取
if (extensionLoaderClassLoaderFirst) {
ClassLoader extensionLoaderClassLoader = ExtensionLoader.class.getClassLoader();
if (ClassLoader.getSystemClassLoader() != extensionLoaderClassLoader) {
urls = extensionLoaderClassLoader.getResources(fileName);
}
}
// 如果找不到任何URL列表,继续尝试去其他当前线程的ClassLoader中寻找
if (urls == null || !urls.hasMoreElements()) {
if (classLoader != null) {
urls = classLoader.getResources(fileName);
} else {
urls = ClassLoader.getSystemResources(fileName);
}
}
// 如果URL列表存在, 逐个遍历资源文件,并加载资源信息到extensionClasses
if (urls != null) {
while (urls.hasMoreElements()) {
java.net.URL resourceURL = urls.nextElement();
loadResource(extensionClasses, classLoader, resourceURL, overridden, excludedPackages);
}
}
} catch (Throwable t) {
logger.error("Exception occurred when loading extension class (interface: " +
type + ", description file: " + fileName + ").", t);
}
}
这里需要注意两个方法: loadResource 和 loadClass。
- loadResource主要用于读取文件操作,并将读取到的信息交给loadClass加载
- loadClass 用于完成类的映射,执行完该方法后,会对几个字段进行更新
- cachedAdaptiveClass: 当前Extension类型对应的AdaptiveExtension类型,只有一个
- cachedWrapperClass: 当前Extension类型对应的所有Wrapper实现类型,无顺序
- chchedActivated: 当前Extension实现自动激活实现缓存( map 类型)
- cachedNames:扩展点实现类对应的名称, 如果配置多个名称则值为第一个
2.2 createAdaptiveExtensionClass 创建扩展点的代理类对象
- 实例化一个新的Adaptive代码生成器, 并生成代码
- 获取类加载器
- 通过扩展点,寻找编译器, 目前有java自带的编译器和javassis编译器
- 编译生成class对象
private Class<?> createAdaptiveExtensionClass() {
// 实例化一个新的Adaptive代码生成器, 并生成代码
String code = new AdaptiveClassCodeGenerator(type, cachedDefaultName).generate();
// 获取类加载器
ClassLoader classLoader = findClassLoader();
// 通过扩展点,寻找编译器, 目前有java自带的编译器和javassis编译器
org.apache.dubbo.common.compiler.Compiler compiler = ExtensionLoader.getExtensionLoader(org.apache.dubbo.common.compiler.Compiler.class).getAdaptiveExtension();
// 编译生成class
return compiler.compile(code, classLoader);
}
2.2.1: 通过 AdaptiveClassCodeGenerator.generate 方法来生成代码
/**
* generate and return class code
*/
public String generate() {
// 如果没有任何方法有Adaptive注解,直接略过
if (!hasAdaptiveMethod()) {
throw new IllegalStateException("No adaptive method exist on extension " + type.getName() + ", refuse to create the adaptive class!");
}
// 用于拼接代码
StringBuilder code = new StringBuilder();
code.append(generatePackageInfo()); // 生成包信息
code.append(generateImports()); // 生成引用信息
code.append(generateClassDeclaration()); // 生成类声明
Method[] methods = type.getMethods(); // 生成每个方法
for (Method method : methods) {
code.append(generateMethod(method));
}
code.append("}"); // 输出最后一个“}”
if (logger.isDebugEnabled()) {
logger.debug(code.toString());
}
return code.toString();
}