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

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

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

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

  1. // 先通过type从缓存中获取ExtensionLoader,如果缓存中不存在,则创建相应的ExtensionLoader放入缓存,再返回
    public static <T> ExtensionLoader<T> getExtensionLoader(Class<T> type) {
  2. if (type == null)
  3. throw new IllegalArgumentException("Extension type == null");
  4. if(!type.isInterface()) {
  5. throw new IllegalArgumentException("Extension type(" + type + ") is not interface!");
  6. }
  7. if(!withExtensionAnnotation(type)) {
  8. throw new IllegalArgumentException("Extension type(" + type +
  9. ") is not extension, because WITHOUT @" + SPI.class.getSimpleName() + " Annotation!");
  10. }
  11.  
  12. ExtensionLoader<T> loader = (ExtensionLoader<T>) EXTENSION_LOADERS.get(type);
  13. if (loader == null) {
  14. EXTENSION_LOADERS.putIfAbsent(type, new ExtensionLoader<T>(type));
  15. loader = (ExtensionLoader<T>) EXTENSION_LOADERS.get(type);
  16. }
  17. return loader;
  18. }

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描述文件中的第二行

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

AdaptiveExtensionFactory的源码如下

  1. @Adaptive
  2. public class AdaptiveExtensionFactory implements ExtensionFactory {
  3.  
  4. private final List<ExtensionFactory> factories;
  5.  
  6. public AdaptiveExtensionFactory() {
  7. ExtensionLoader<ExtensionFactory> loader = ExtensionLoader.getExtensionLoader(ExtensionFactory.class);
  8. List<ExtensionFactory> list = new ArrayList<ExtensionFactory>();
  9. for (String name : loader.getSupportedExtensions()) {
  10. list.add(loader.getExtension(name));
  11. }
  12. factories = Collections.unmodifiableList(list);
  13. }
  14.  
  15. public <T> T getExtension(Class<T> type, String name) {
  16. for (ExtensionFactory factory : factories) {
  17. T extension = factory.getExtension(type, name);
  18. if (extension != null) {
  19. return extension;
  20. }
  21. }
  22. return null;
  23. }
  24.  
  25. }

总结:

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

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. Scrapy Shell的使用

    Scrapy终端是一个交互终端,我们可以在未启动spider的情况下尝试及调试代码,也可以用来测试XPath或CSS表达式,查看他们的工作方式,方便我们爬取的网页中提取的数据. 如果安装了 IPyth ...

  2. SpringMVC+Shiro不拦截静态资源配置

    最近在弄SpringMVC与Shiro整合,发现如果将DispatcherServlet拦截 *.do这样的URL,就不存在访问不到静态资源的问题.如果DispatcherServlet改为拦截“/” ...

  3. 浏览器内核 Trident Gecko Presto Webkit

    Trident内核:IE,MaxThon,TT,The World,360,搜狗浏览器等 Gecko内核:Netscape6及以上版本,FF,MozillaSuite/SeaMonkey等 Prest ...

  4. Spring Boot 2下使用Feign找不到@EnableFeignClients的解决办法

    最近在实践Spring Boot 2+Spring Cloud(Finchley.M9),在用到Feign的时候发现@EnableFeignClients注解开不了,独立使用Feign是可以的,但就是 ...

  5. c++中sizeof的理解

    1. 例题 #include <iostream> class A {}; class B { char m_data; }; class C { ]; }; class D { char ...

  6. Ant和Maven

    Ant和Maven都是基于Java的构建(build)工具.理论上来说,有些类似于(Unix)C中的make ,但没有make的缺陷.Ant是软件构建工具,Maven的定位是软件项目管理和理解工具. ...

  7. 转---变量LEGB规则

    Python 变量作用域的规则是 LEGB LEGB含义解释: L -- Local(function):函数内的名字空间 E -- Enclosing function locals:外部嵌套函数的 ...

  8. DataReader分页性能测试

    参考程序地址:http://www.cnblogs.com/eaglet/archive/2008/10/09/1306806.html 最近遇见程序慢的问题,使用的DataReader,猜想是分页导 ...

  9. hackrf入门

    http://www.hackrf.net/hackrf%E4%B8%8Egnuradio%E5%85%A5%E9%97%A8%E6%8C%87%E5%8D%97/

  10. 课堂测试——jsp登录界面设计

    实现结果:在login.jsp页面提交用户名和密码(可以验证是否为空),点击登录跳转到loginResult.jsp页面进行验证并显示结果 JSP + JDBC + MySQL login.jsp 设 ...