源码分析:

  1. /**
  2. * 获取扩展类
  3. */
  4. @SuppressWarnings("unchecked")
  5. public T getExtension(String name) {
  6. if (StringUtils.isEmpty(name)) {
  7. throw new IllegalArgumentException("Extension name == null");
  8. }
  9. // 获取默认的拓展实现类
  10. if ("true".equals(name)) {
  11. return getDefaultExtension();
  12. }
  13. // Holder用于持有目标对象
  14. final Holder<Object> holder = getOrCreateHolder(name);
  15. Object instance = holder.get();
  16. // 双重检查
  17. if (instance == null) {
  18. synchronized (holder) {
  19. instance = holder.get();
  20. if (instance == null) {
  21. // 创建拓展实例
  22. instance = createExtension(name);
  23. // 设置实例到 holder 中
  24. holder.set(instance);
  25. }
  26. }
  27. }
  28. return (T) instance;
  29. }
  1. // 创建拓展对象
  2. @SuppressWarnings("unchecked")
  3. private T createExtension(String name) {
  4. Class<?> clazz = getExtensionClasses().get(name);
  5. if (clazz == null) {
  6. throw findException(name);
  7. }
  8. try {
  9. T instance = (T) EXTENSION_INSTANCES.get(clazz);
  10. if (instance == null) {
  11. // 通过反射创建实例
  12. EXTENSION_INSTANCES.putIfAbsent(clazz, clazz.newInstance());
  13. instance = (T) EXTENSION_INSTANCES.get(clazz);
  14. }
  15. // 向实例中注入依赖
  16. injectExtension(instance);
  17. Set<Class<?>> wrapperClasses = cachedWrapperClasses;
  18. if (CollectionUtils.isNotEmpty(wrapperClasses)) {
  19. // 循环创建 Wrapper 实例
  20. for (Class<?> wrapperClass : wrapperClasses) {
  21. // 将当前 instance 作为参数传给 Wrapper 的构造方法,并通过反射创建 Wrapper 实例。
  22. // 然后向 Wrapper 实例中注入依赖,最后将 Wrapper 实例再次赋值给 instance 变量
  23. instance = injectExtension((T) wrapperClass.getConstructor(type).newInstance(instance));
  24. }
  25. }
  26. return instance;
  27. } catch (Throwable t) {
  28. throw new IllegalStateException("Extension instance (name: " + name + ", class: " + type
  29. + ") couldn't be instantiated: " + t.getMessage(), t);
  30. }
  31. }
  1. // 从配置文件中加载所有的拓展类,可得到“配置项名称”到“配置类”的映射关系表
  2. private Map<String, Class<?>> getExtensionClasses() {
  3. // 从缓存中获取已加载的拓展类
  4. Map<String, Class<?>> classes = cachedClasses.get();
  5. // 双重检查
  6. if (classes == null) {
  7. synchronized (cachedClasses) {
  8. classes = cachedClasses.get();
  9. if (classes == null) {
  10. // 加载拓展类
  11. classes = loadExtensionClasses();
  12. cachedClasses.set(classes);
  13. }
  14. }
  15. }
  16. return classes;
  17. }
  1. // synchronized in getExtensionClasses
  2. private Map<String, Class<?>> loadExtensionClasses() {
  3. cacheDefaultExtensionName();
  4.  
  5. Map<String, Class<?>> extensionClasses = new HashMap<>();
  6. // 加载指定文件夹下的配置文件
  7. loadDirectory(extensionClasses, DUBBO_INTERNAL_DIRECTORY, type.getName());
  8. loadDirectory(extensionClasses, DUBBO_INTERNAL_DIRECTORY, type.getName().replace("org.apache", "com.alibaba"));
  9. loadDirectory(extensionClasses, DUBBO_DIRECTORY, type.getName());
  10. loadDirectory(extensionClasses, DUBBO_DIRECTORY, type.getName().replace("org.apache", "com.alibaba"));
  11. loadDirectory(extensionClasses, SERVICES_DIRECTORY, type.getName());
  12. loadDirectory(extensionClasses, SERVICES_DIRECTORY, type.getName().replace("org.apache", "com.alibaba"));
  13. return extensionClasses;
  14. }
  1. private void loadDirectory(Map<String, Class<?>> extensionClasses, String dir, String type) {
  2. // fileName = 文件夹路径 + type 全限定名
  3. String fileName = dir + type;
  4. try {
  5. Enumeration<java.net.URL> urls;
  6. ClassLoader classLoader = findClassLoader();
  7. // 根据文件名加载所有的同名文件
  8. if (classLoader != null) {
  9. urls = classLoader.getResources(fileName);
  10. } else {
  11. urls = ClassLoader.getSystemResources(fileName);
  12. }
  13. if (urls != null) {
  14. while (urls.hasMoreElements()) {
  15. java.net.URL resourceURL = urls.nextElement();
  16. // 加载资源
  17. loadResource(extensionClasses, classLoader, resourceURL);
  18. }
  19. }
  20. } catch (Throwable t) {
  21. logger.error("Exception occurred when loading extension class (interface: " + type + ", description file: "
  22. + fileName + ").", t);
  23. }
  24. }

dubbo SPI机制的更多相关文章

  1. 【Dubbo源码阅读系列】之 Dubbo SPI 机制

    最近抽空开始了 Dubbo 源码的阅读之旅,希望可以通过写文章的方式记录和分享自己对 Dubbo 的理解.如果在本文出现一些纰漏或者错误之处,也希望大家不吝指出. Dubbo SPI 介绍 Java ...

  2. Dubbo SPI 机制源码分析(基于2.7.7)

    Dubbo SPI 机制涉及到 @SPI.@Adaptive.@Activate 三个注解,ExtensionLoader 作为 Dubbo SPI 机制的核心负责加载和管理扩展点及其实现.本文以 E ...

  3. Dubbo SPI机制之三Adaptive自适应功能

    JDK标准中SPI机制的一个问题就是其一次性实例化扩展点所有实现,如果有扩展实现初始化很耗时,但如果没用上也加载,会很浪费资源:扩展点加载失败,其他扩展点都用不了了.Dubbo是如何解决该问题动态的选 ...

  4. Dubbo SPI机制之一JDK中的SPI

    首先简单阐述下什么是SPI:SPI 全称为 (Service Provider Interface) ,是JDK内置的一种服务提供发现机制.目前有不少框架用它来做服务的扩展发现,简单来说,就是一种动态 ...

  5. 面试常问的dubbo的spi机制到底是什么?

    前言 dubbo是一款微服务开发框架,它提供了 RPC通信 与 微服务治理 两大关键能力.作为spring cloud alibaba体系中重要的一部分,随着spring cloud alibaba在 ...

  6. SPI 机制-插件化扩展功能

    SPI(Service Provider Interfaces),中文直译服务提供者接口,一种服务发现机制.可能很多人都不太熟悉这个机制,但是平常或多或少都用到了这个机制,比如我们使用 JDBC 连接 ...

  7. Dubbo SPI源码解析①

    目录 0.Java SPI示例 1.Dubbo SPI示例 2.Dubbo SPI源码分析 ​ SPI英文全称为Service Provider Interface.它的作用就是将接口实现类的全限定名 ...

  8. Dubbo 源码分析 - SPI 机制

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

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

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

随机推荐

  1. eigenvalues problem

    由于在看paper中经常会看到generalized eigenvalues.eigenvalues problem等字眼,今晚终于开始认真地重新看了一下线性代数中这部分内容.下面是在学习过程中找出来 ...

  2. harbor报错解决

    1. [root@host-10-1-1-71 harbor]# docker login 10.1.1.71:5000Username (admin): Password: Error respon ...

  3. 关于img标签浏览器自带的边框,清除边框的解决方式(即img[src=""] img无路径情况下,灰色边框去除解决方法)

    详解img[src=""] img无路径情况下,灰色边框去除解决方法 1.Js解决办法 <html> <head> <meta charset=&qu ...

  4. linux环境下安装yaf

    一.ubuntu环境 1.首先到http://pecl.php.net/get/yaf下载最新版本的yaf,我的是yaf-2.2.9.tgz. 2.解压 tar -zxvf yaf-2.2.9.tgz ...

  5. jquery实现分页效果

    通过jq实现分页的原理如下:将所有条数加载到页面中,根据每页放特定条数(例如 5 条)获取jquery对象索引,使部分条数显示,其他条数隐藏. 前提:引入jquery.js 代码 <!DOCTY ...

  6. Hand on Machine Learning 第三章:分类器

    1. 获取数据 使用MNIST数据集练习分类任务 from sklearn.datasets import fetch_mldata from scipy.io import loadmat mnis ...

  7. css 命名 有的加# ,有的加点 ,有的没加。请问下都在什么情况下用的?

    [nav{}]这样的样式是给特定的标签直接定义样式时使用的,这个样式名称是跟标签是相对应的,比如我要给<p></p>这个标签设置样式,那我就可以直接写:p{样式}就可以,但是这 ...

  8. 交换机安全学习笔记 第六章 IPV4 ARP攻击

    ARP欺骗攻击 常用工具:  dsniff(Linux/windows).ettercap(Linux/windows).cain(仅windows). ARP欺骗攻击的目的是嗅探发往某主机的所有IP ...

  9. oracle中的多表查询和子查询以及一些注意事项

    多表查询就是使用两张表及其以上的查询.首先需要知道几个名词,笛卡尔积,内连接,外连接,子查询. 1)笛卡尔积 所谓笛卡尔积其实就是两张表数据的条数相乘得到的最后结果,例如表1有10条数据,表2有4条数 ...

  10. Vue.nextTick 的原理和用途

    转载自https://segmentfault.com/a/1190000012861862 概览 官方文档说明: 用法: 在下次 DOM 更新循环结束之后执行延迟回调.在修改数据之后立即使用这个方法 ...