IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 开发测试 -> 二、dubbo spi 源码分析 -> 正文阅读

[开发测试]二、dubbo spi 源码分析

二、dubbo spi 源码分析

1、ExtensionLoader

ExtensionLoader 是dubbo spi 主要实现类,从字面意思可以看出是扩展加载器,是将配置文件与java的对应关系进行组装处理,从而得到我们需要的实际扩展处理类

ExtensionLoader 类中有两个静态属性 EXTENSION_LOADERS (缓存所有的ExtensionLoader) 和 EXTENSION_INSTANCES (缓存扩展实现)

 private static final ConcurrentMap<Class<?>, ExtensionLoader<?>> EXTENSION_LOADERS = new ConcurrentHashMap<>(64);

    private static final ConcurrentMap<Class<?>, Object> EXTENSION_INSTANCES = new ConcurrentHashMap<>(64);

1.1 getExtensionLoader 方法

在dubbo源码中获取扩展加载器的主要逻辑是在getExtensionLoader静态方法中

  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 an interface!");
        }
        //判断接口有没有声明@SPI注解
        if (!withExtensionAnnotation(type)) {
            throw new IllegalArgumentException("Extension type (" + type +
                    ") is not an extension, because it is NOT annotated with @" + SPI.class.getSimpleName() + "!");
        }
        //先去缓存中查找有没有对应的扩展类加载器
        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;
    }

1.2 ExtensionLoader 构造方法 new ExtensionLoader(type)

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

可以看到如果参数type 不是 ExtensionFactory 将会获取ExtensionFactory 的类加载器,接着获取

ExtensionFactory 的自适应扩展类。

 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);

}

org.apache.dubbo.common.extension.ExtensionFactory 文件中声明了以下SPI 实现:

adaptive=org.apache.dubbo.common.extension.factory.AdaptiveExtensionFactory
spi=org.apache.dubbo.common.extension.factory.SpiExtensionFactory

ExtensionFactory 也是一个被标记的扩展接口,再dubbo 中配置了两个扩展实现。而在dubbo-config-spring 的配置中我们可以找到另一个实现类:

spring=org.apache.dubbo.config.spring.extension.SpringExtensionFactory

获取到了ExtensionFactory 的扩展类加载器后,getAdaptiveExtension() 会做哪些事呢?

1.3 getAdaptiveExtension 方法

 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;
    }
    private T createAdaptiveExtension() {
        try {
            return injectExtension((T) getAdaptiveExtensionClass().newInstance());
        } catch (Exception e) {
            throw new IllegalStateException("Can't create adaptive extension " + type + ", cause: " + e.getMessage(), e);
        }
    }
    private Class<?> getAdaptiveExtensionClass() {
        //根据对应的SPI文件加载扩展类并缓存,细节此处不展开
        getExtensionClasses();
        // 如果存在被@Adaptive修饰的类则直接返回此类
        if (cachedAdaptiveClass != null) {
            return cachedAdaptiveClass;
        }
        // 动态生成Xxxx$Adaptive类
        return cachedAdaptiveClass = createAdaptiveExtensionClass();
    }
//代理类
package com.jufeng.learn.other.api.dubbo.spi.demo03;
import com.alibaba.dubbo.common.extension.ExtensionLoader;
public class SimpleEcho$Adaptive implements com.jufeng.learn.other.api.dubbo.spi.demo03.SimpleEcho {
  public void printA(java.lang.String arg0) {
    throw new UnsupportedOperationException("method public abstract void com.jufeng.learn.other.api.dubbo.spi.demo03.SimpleEcho.printA(java.lang.String) of interface com.jufeng.learn.other.api.dubbo.spi.demo03.SimpleEcho is not adaptive method!");
  }
  public void printB(com.alibaba.dubbo.common.URL arg0, java.lang.String arg1) {
    if (arg0 == null) throw new IllegalArgumentException("url == null");
    com.alibaba.dubbo.common.URL url = arg0;
    String extName = url.getParameter("simple.echo");
    if(extName == null) throw new IllegalStateException("Fail to get extension(com.jufeng.learn.other.api.dubbo.spi.demo03.SimpleEcho) name from url(" + url.toString() + ") use keys([simple.echo])");
    com.jufeng.learn.other.api.dubbo.spi.demo03.SimpleEcho extension = (com.jufeng.learn.other.api.dubbo.spi.demo03.SimpleEcho)ExtensionLoader.getExtensionLoader(com.jufeng.learn.other.api.dubbo.spi.demo03.SimpleEcho.class).getExtension(extName);extension.printB(arg0, arg1);
  }
}

至此,自适应扩展类就被加载完成,有兴趣可以看getExtensionClasses 方法是怎么实现读取 SPI配置文件以及 @Adaptive 和 URL 参数的解析校验。

下面一节,我们分析ExtensionFactory 的作用,以及在Dubbo是如何将SpringIOC 容器中的实例整合到Dubbo框架中。

2. ExtensionFactory

ExtensionFactory是dubbo框架中被标记的一个扩展接口,默认实现为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);
    }

    @Override
    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;
    }

}
在无参的构造方法中可以看到,它会获取ExtensionFactory 的扩展类加载器,并将所有的实现类全部放入factories 属性中。而dubbo 以及 dubbo-config-spring 中配置的

spi=org.apache.dubbo.common.extension.factory.SpiExtensionFactory

spring=org.apache.dubbo.config.spring.extension.SpringExtensionFactory 都会被放入 factories 中。

SpringExtensionFactory 是我们重点关注的对象,下面看看它的实现:

public class SpringExtensionFactory implements ExtensionFactory {
    private static final Logger logger = LoggerFactory.getLogger(SpringExtensionFactory.class);
    private static final Set<ApplicationContext> CONTEXTS = new ConcurrentHashSet<ApplicationContext>();
    public static void addApplicationContext(ApplicationContext context) {
        CONTEXTS.add(context);
        if (context instanceof ConfigurableApplicationContext) {
            ((ConfigurableApplicationContext) context).registerShutdownHook();
        }
    }
    public static void removeApplicationContext(ApplicationContext context) {
        CONTEXTS.remove(context);
    }
    public static Set<ApplicationContext> getContexts() {
        return CONTEXTS;
    }
    // currently for test purpose
    public static void clearContexts() {
        CONTEXTS.clear();
    }
    @Override
    @SuppressWarnings("unchecked")
    public <T> T getExtension(Class<T> type, String name) {

        //SPI should be get from SpiExtensionFactory
        if (type.isInterface() && type.isAnnotationPresent(SPI.class)) {
            return null;
        }
        for (ApplicationContext context : CONTEXTS) {
            T bean = getOptionalBean(context, name, type);
            if (bean != null) {
                return bean;
            }
        }
        return null;
    }

}


可以看到 SpringExtensionFactory 中维护了Spring上下文对象ApplicationContext,所以只要Spring的上下文对象被放入 SpringExtensionFactory CONTEXTS 属性中,Dubbo 就可以获取到SpringIOC 中的实例。

以ServiceBean 为例,在Dubbo中是对服务提供接口的一次封装,用于注入到Spring中,那么Dubbo 在暴露接口的时候是需要拿到IOC 中的一些实例,所以Dubbo是怎么做的呢?下面来看ServiceBean 的实现

public class ServiceBean<T> extends ServiceConfig<T> implements InitializingBean, DisposableBean,
        ApplicationContextAware, BeanNameAware, ApplicationEventPublisherAware {
         @Override
    public void setApplicationContext(ApplicationContext applicationContext) {
        this.applicationContext = applicationContext;
        SpringExtensionFactory.addApplicationContext(applicationContext);
    }
......        
}

可以看到 ServiceBean 实现了 ApplicationContextAware ,而实现了ApplicationContextAware 接口将会在bean 的初始化之前执行,在执行setApplicationContext 方法时,会执行 SpringExtensionFactory.addApplicationContext(applicationContext) 这行代码,所以Spring的上下文对象就会被写入到 SpringExtensionFactory类的静态成员属性中,当dubbo需要取到 Spring IOC 中的对象时就可以根据 AdaptiveExtensionFactory.getExtension()方法进行获取(此处只是举例,在Spring 中 dubbo 的启动方式,服务暴露等详细内容将在其他章节中解析。)

  开发测试 最新文章
pytest系列——allure之生成测试报告(Wind
某大厂软件测试岗一面笔试题+二面问答题面试
iperf 学习笔记
关于Python中使用selenium八大定位方法
【软件测试】为什么提升不了?8年测试总结再
软件测试复习
PHP笔记-Smarty模板引擎的使用
C++Test使用入门
【Java】单元测试
Net core 3.x 获取客户端地址
上一篇文章      下一篇文章      查看所有文章
加:2022-01-16 13:23:15  更:2022-01-16 13:24:07 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/18 4:46:57-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码