ExtensionLoader类是整个SPI的核心类,每个SPI都会对应一个ExtensionLoader类实例,这个类的构造方法如下:

private ExtensionLoader(Class<?> type) {
this.type = type;
objectFactory = (type == ExtensionFactory.class ? null : ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension());
}

里面的objectFactory对应的就是ExtensionFactory类的实例,通过源码能发现,ExtensionFactory自身也是一个SPI接口,那么它也会有一个对应的ExtensionLoader类实例,这个类实例中的objectFactory属性为null ,而其他的ExtensionLoader类实例中的 objectFactory属性是 : ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension()

我们就先来分析下ExtensionLoader.getExtensionLoader(ExtensionFactory.class) 这句代码。

// 先通过type从缓存中获取ExtensionLoader,如果缓存中不存在,则创建相应的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!");
}
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;
}

getAdaptiveExtension()内部的调用过程如下(注意这是一个实例方法):

-> if(cachedAdaptiveInstance.get() == null){ createAdaptiveExtension() }

->getAdaptiveExtensionClass()   //下面的调用有两个分支

// 分支1
    ->getExtensionClasses()
      ->loadExtensionClasses()
        ->loadFile(extensionClasses, DUBBO_INTERNAL_DIRECTORY);

     injectExtension   //完成注入,这是 ExtensionFactory 类的作用之所在 

               // 分支2

               ->createAdaptiveExtensionClass()

injectExtension

经过上述分析,可以得出 ExtensionLoader.getExtensionLoader(ExtensionFactory.class) 返回的是 com.alibaba.dubbo.common.extension.factory.AdaptiveExtensionFactory类的实例,这个类在ExtensionFactory的SPI描述文件中的第二行

spring=com.alibaba.dubbo.config.spring.extension.SpringExtensionFactory
adaptive=com.alibaba.dubbo.common.extension.factory.AdaptiveExtensionFactory
spi=com.alibaba.dubbo.common.extension.factory.SpiExtensionFactory

AdaptiveExtensionFactory的源码如下

@Adaptive
public class AdaptiveExtensionFactory implements ExtensionFactory { private final List<ExtensionFactory> factories; public AdaptiveExtensionFactory() {
ExtensionLoader<ExtensionFactory> loader = ExtensionLoader.getExtensionLoader(ExtensionFactory.class);
List<ExtensionFactory> list = new ArrayList<ExtensionFactory>();
for (String name : loader.getSupportedExtensions()) {
list.add(loader.getExtension(name));
}
factories = Collections.unmodifiableList(list);
} public <T> T getExtension(Class<T> type, String name) {
for (ExtensionFactory factory : factories) {
T extension = factory.getExtension(type, name);
if (extension != null) {
return extension;
}
}
return null;
} }

总结:

通过上述分析,可以知道:

1. 除了ExtensionFactory之外,其他的SPI接口对应的ExtensionLoader类实例中的 objectFactory属性都是AdaptiveExtensionFactory的实例对象。

2.  且这些AdaptiveExtensionFaatory实例都是同一个,这是因为ExtensionLoader的类属性会会在EXTENSION_LOADERS中缓存创建好的loader,每个loader又会在其的实例属性cachedAdaptiveClass缓存这个adaptive性质的Extension类。

3.  ExtensionLoader的injectExtension方法完成的注入工作正是objectFactory(ExtensionFactory类)的真正作用。这个作用留待下一篇再做分析。

dubbo源码分析3——SPI机制中的ExtensionLoader类的objectFactory属性分析的更多相关文章

  1. dubbo源码分析2——SPI机制中的SPI实现类的读取和预处理

    SPI机制中的SPI实现类的读取和预处理是由ExtensionLoader类的loadFile方法来完成的 loadFile方法的作用是读取dubbo的某个SPI接口的spi描述文件,然后进行缓存,缓 ...

  2. Dubbo源码解析之SPI(一):扩展类的加载过程

    Dubbo是一款开源的.高性能且轻量级的Java RPC框架,它提供了三大核心能力:面向接口的远程方法调用.智能容错和负载均衡,以及服务自动注册和发现. Dubbo最早是阿里公司内部的RPC框架,于 ...

  3. dubbo源码分析6——SPI机制中的AOP

    在 ExtensionLoader 类的loadFile方法中有下图的这段代码: 类如现在这个ExtensionLoader中的type 是Protocol.class,也就是SPI接口的实现类中Xx ...

  4. Dubbo源码学习之-SPI介绍

    前言 学习之路还是要戒骄戒躁,一以贯之的积累前行.之前的公司部门技术达人少,自己总向往那些技术牛人多的团队,想象自己进去之后能跟别人学到多少东西.如今进到一个这样的团队之后,却发现之前自己的想法过于幼 ...

  5. dubbo源码阅读之SPI

    dubbo SPI SPI,全程Service Provider interface, java中的一种借口扩展机制,将借口的实现类注明在配置文件中,程序在运行时通过扫描这些配置文件从而获取全部的实现 ...

  6. 读Dubbo源码,学习SPI

    核心类 ExtensionLoader 使用方法 定义接口,使用@SPI标记 @SPI("impl1") public interface SimpleExt { // @Adap ...

  7. Dubbo 源码分析 - SPI 机制

    1.简介 SPI 全称为 Service Provider Interface,是 Java 提供的一种服务发现机制.SPI 的本质是将接口实现类的全限定名配置在文件中,并由服务加载器读取配置文件,加 ...

  8. dubbo源码分析4——SPI机制_ExtensionFactory类的作用

    ExtensionFactory的源码: @SPI public interface ExtensionFactory { /** * Get extension. * * @param type o ...

  9. Dubbo源码分析之 SPI(一)

    一.概述 dubbo SPI 在dubbo的作用是基础性的,要想分析研究dubbo的实现原理.dubbo源码,都绕不过 dubbo SPI,掌握dubbo SPI 是征服dubbo的必经之路. 本篇文 ...

随机推荐

  1. go websocket

    websocket介绍 The WebSocket Protocol  RFC6455,这个是WebSocket的RFC文档,所以内容非常全面(当然只涉及协议,不涉及具体实现),不过内容太多,如果是初 ...

  2. python APScheduler

    简介 APScheduler基于Quartz的一个Python定时任务框架,实现了Quartz的所有功能,使用起来十分方便.提供了基于日期.固定时间间隔以及crontab类型的任务,并且可以持久化任务 ...

  3. o(1), o(n), o(logn), o(nlogn)

    转自:https://blog.csdn.net/Mars93/article/details/75194138 在描述算法复杂度时,经常用到o(1), o(n), o(logn), o(nlogn) ...

  4. 从LIst集合中安全的删除元素

    package cn.rocker.list; import java.util.ArrayList; import java.util.Iterator; import java.util.List ...

  5. ansible Api 2.3-2.4

    官网示例(python3) 说明: 在学习2.0 api的过程中遇到了一个坑,最新版的ansible(2.4)和2.3版本api引用时发生了变化,本文主要使用2.3 api进行操作,2.4只做分析 a ...

  6. MacOS环境中 python3 部署

    MacOS环境中 python3 部署 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.在MacOS安装Python3.6 1>.打开python关于MacOS版本的官方网 ...

  7. java中用jdom创建xml文档/将数据写入XML中

    import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; i ...

  8. Shuttle 学习

    见  http://blog.csdn.net/liu765023051/article/details/38521039

  9. 介绍3款Markdown编辑器

    为什么写此篇  自从CSDN的博客有了Markdown后,慢慢的了解并学会了用Markdown语法写博客.但CSDN博客是在浏览器中使用,于是一直寻找离线的Markdown编辑器.  网上先是找到了M ...

  10. 057、macvlan 网络隔离和连通(2019-03-26 周二)

    参考https://www.cnblogs.com/CloudMan6/p/7400580.html   在上一节中,两个host上四个容器的网络信息如下,然后进行网络连通性测试,可见通vlan的容器 ...