我们说dubbo的spi机制和Java提供的spi机制,有一个很大的区别,dubbo的spi机制中,需要在文件中,指定key,我们在使用的时候可以根据key,只加载我们需要使用的实现类,那除了直接在文件中,通过
key=com.xxx.interfaceImpl这种方式之外,还可以通过@Extension这个注解来指定key,dubbo源码在解析的时候,会判断,如果没有在文件中指定key,会解析其实现类上是否有这个注解

文章中,指定路径指:META-INF/services
指定文件是指这个路径下的文件

com.alibaba.dubbo.common.extension.ExtensionLoader#loadClass

在spi机制被使用的时候,是会去指定路径下,解析指定的文件,然后从文件中解析出对应key和value,解析之后,会有一系列逻辑的判断,上面的这个方法,就是解析之后,对实现类进行的一系列判断,具体是如何执行到这一个方法的,在前面 dubbo源码之SPI机制源码中有介绍

其实大致就是说:如果在调用spi的时候,会一次去指定路径下解析指定的文件,解析到文件之后,会一行一行的解析,以 "="为分隔符,前面的是key,后面的是value,解析到之后,会根据value(全类名),生成对应的class文件,然后进入到这个方法中,对class进行解析

/*** 这个方法主要是将name和clazz赋值到extensionClasses中,只是在put之前,会有一系列的逻辑判断,会区分出来是哪种类型的类* @param extensionClasses* @param resourceURL* @param clazz* @param name* @throws NoSuchMethodException*/
private void loadClass(Map<String, Class<?>> extensionClasses, java.net.URL resourceURL, Class<?> clazz, String name) throws NoSuchMethodException {/*** 1.判断clazz是否是type的实现类* 如果type是Protocol,那么这里的clazz就是文件中配置的HttpProtocol实现类* 如果不是type的实现类,就抛出异常*/if (!type.isAssignableFrom(clazz)) {throw new IllegalStateException("Error when load extension class(interface: " +type + ", class line: " + clazz.getName() + "), class "+ clazz.getName() + "is not subtype of interface.");}/*** 2.判断当前实现类上是否有@Adaptive注解,需要注意的是:一个接口,只允许有一个adaptive实现类* 如果有多个,就抛出异常* cachedAdaptiveClass中保存的就是type对应的adaptive实现类,这里获取到的是我们自己定义的adaptive实现类*/if (clazz.isAnnotationPresent(Adaptive.class)) {if (cachedAdaptiveClass == null) {cachedAdaptiveClass = clazz;} else if (!cachedAdaptiveClass.equals(clazz)) {throw new IllegalStateException("More than 1 adaptive class found: "+ cachedAdaptiveClass.getClass().getName()+ ", " + clazz.getClass().getName());}} else if (isWrapperClass(clazz)) {/*** 在判断是否是包装类的时候,就看对应类中是否有目标接口的构造函数* 3.wrapper类的处理,如果当前clazz是type实现类的包装类,就暂时将包装类存入到一个集合中* CarWrapper就会进入到这里来处理*/Set<Class<?>> wrappers = cachedWrapperClasses;if (wrappers == null) {cachedWrapperClasses = new ConcurrentHashSet<Class<?>>();wrappers = cachedWrapperClasses;}wrappers.add(clazz);} else {/*** 4.1 进入到这里,表示既不是包装类,也没有添加@Adaptive注解* 必须要有无参构造函数,因为是通过class.newInstance()来初始化的*/clazz.getConstructor();/*** 4.2 如果在META-INF下的文件中,没有配置name,就从实现类上去判断,是否有添加@Extension注解,如果有添加,就返回* @Extension 注解对应的value*/if (name == null || name.length() == 0) {name = findAnnotationName(clazz);if (name.length() == 0) {throw new IllegalStateException("No such extension name for the class " + clazz.getName() + " in the config " + resourceURL);}}/*** 4.3 对name进行拆分* 并且判断是否有添加@Activate注解*/String[] names = NAME_SEPARATOR.split(name);if (names != null && names.length > 0) {Activate activate = clazz.getAnnotation(Activate.class);if (activate != null) {cachedActivates.put(names[0], activate);}for (String n : names) {if (!cachedNames.containsKey(clazz)) {cachedNames.put(clazz, n);}Class<?> c = extensionClasses.get(n);if (c == null) {extensionClasses.put(n, clazz);} else if (c != clazz) {throw new IllegalStateException("Duplicate extension " + type.getName() + " name " + n + " on " + c.getName() + " and " + clazz.getName());}}}}
}

我们要关心的是4.2这个注释

我们可以看到,有一个判断:
这里的判断也很简单,如果name为null,就表示我在文件中是这样来配置的:
com.xxxx.xxxx.InterfaceImpl
正常情况下,配置的时候,是需要指定key的,那如果是这种情况,dubbo会取实现类上解析是否有@Extension注解
也就是下面这个方法中

private String findAnnotationName(Class<?> clazz) {com.alibaba.dubbo.common.Extension extension = clazz.getAnnotation(com.alibaba.dubbo.common.Extension.class);/*** 1.如果没有添加注解,就取class的simpleName,然后判断是否是以接口名结尾的,如果是,就截取其前面部分作为name* RedCarInterface,如果实现类名是这个,就会截取red作为name*/if (extension == null) {String name = clazz.getSimpleName();if (name.endsWith(type.getSimpleName())) {name = name.substring(0, name.length() - type.getSimpleName().length());}return name.toLowerCase();}/*** 2.如果配置了注解,就返回其value值,value值就是实现类对应的name*/return extension.value();
}

这里可以看到,如果@Extension注解也没有加,dubbo还会进行一次挣扎,也就是直接解析实现类,取其simpleName,然后判断实现类是否是以接口结尾的,其实举个例子就是这样的
假如我自定义了一个protocol的实现类:MySelfProtocol,有三种情况
1.如果我在文件中指定:mySelf=com.xxx.MySelfProtocol,那就会使用文件中的name作为key(name)
2.如果我既没有在文件中指定name,但是添加了@Extension(value = “mySelf”),那就会使用这里的value作为name来赋值
3.如果我既没有在文件中指定,也没有在实现类上添加注解,那就会解析MySelfProtocol这个字符串,然后截取mySelf作为name,并将mySelf转换为小写

dubbo之SPI扩展机制注解:@Extension注解的作用相关推荐

  1. Dubbo第三讲:Dubbo的可扩展机制SPI源码解析

    本文是Dubbo第三讲:Dubbo的可扩展机制SPI源码解析 文章目录 1.Dubbo SPI机制 1.1.Dubbo具有良好拓展性的原因 1.2.Dubbo SPI和Java SPI的区别? 1.3 ...

  2. Dubbo的可扩展机制SPI源码解析

    内容概要: Dubbo SPI案例演示 Dubbo SPI主流程源码解析 Dubbo中的依赖注入源码解析 Dubbo中的AOP实现源码解析 Dubbo中的Adaptive机制源码解析 文章目录 一.D ...

  3. dubbo的可扩展机制SPI源码解析(二)

    1.基本流程 2.AOP 3.IOC 4.AdaptiveExtension 5.ActivateExtension getExtension(name) getAdaptiveExtension(U ...

  4. 聊聊Dubbo - Dubbo可扩展机制源码解析

    2019独角兽企业重金招聘Python工程师标准>>> 摘要: 在Dubbo可扩展机制实战中,我们了解了Dubbo扩展机制的一些概念,初探了Dubbo中LoadBalance的实现, ...

  5. dubbo源码分析系列(1)扩展机制的实现

    1 系列目录 dubbo源码分析系列(1)扩展机制的实现 dubbo源码分析系列(2)服务的发布 dubbo源码分析系列(3)服务的引用 dubbo源码分析系列(4)dubbo通信设计 2 SPI扩展 ...

  6. 阿里面试真题:Dubbo的SPI机制

    点赞再看,养成习惯,微信搜一搜[三太子敖丙]关注这个喜欢写情怀的程序员. 本文 GitHub https://github.com/JavaFamily 已收录,有一线大厂面试完整考点.资料以及我的系 ...

  7. SpringBoot解耦的扩展机制 Spring Factories介绍及使用

    一.什么是 SPI机制 Spring Boot中有一种非常解耦的扩展机制:Spring Factories.这种扩展机制实际上是仿照Java中的SPI扩展机制来实现的.SPI的全名为Service P ...

  8. SpringBoot扩展机制——spring factories

    介绍 Spring Boot中有一种非常解耦的扩展机制:Spring Factories.这种扩展机制实际上是仿照 Java 中的 SPI 扩展机制来实现的.它在META-INF/spring.fac ...

  9. java spi 扩展_【扩展和解耦】JAVA原生SPI实现插件扩展

    Java极客  |  作者  /  铿然一叶 这是Java极客的第 81 篇原创文章 相关阅读: 1. 什么是插件 通俗的讲插件有以下特征: 1.增加或者替换已有能力 2.不影响原有功能 3.对原有系 ...

  10. Dubbo源码分析(三)Dubbo中的SPI和自适应扩展机制

    前言 我们在往期文章中,曾经深入分析过Java的SPI机制,它是一种服务发现机制.具体详见:深入理解JDK的SPI机制 在继续深入Dubbo之前,我们必须先要明白Dubbo中的SPI机制.因为有位大神 ...

最新文章

  1. 关于研发效能提升的思考,每个P8以及以上都应该懂!
  2. 什么是产品Backlog(Product Backlog)?
  3. 10.1.1 head标签
  4. oracle的asmcmd获取归档日志,分析oracle的联机日志和归档日志
  5. origin遇到不适当的参数_Origin教程|如何更改Lable和设置非均匀坐标
  6. C#使用Objects Comparer进行对象比较
  7. datagridview列 值提取_Excel学校如何提取教职工员工名单-Leo老师
  8. 修改配置_iMC服务器修改IP地址的配置
  9. 第二章 如何在VS2008里面编译CG
  10. 详解.NET IL代码
  11. myeclipse php插件phpeclipse安装及配置(插件式安装)
  12. 随机数公式Random
  13. 沪深300指数的跟踪基金排名
  14. 千万不要和女程序员做同事!
  15. 第41课:Checkpoint彻底解密:Checkpoint的运行原理和源码实现彻底详解
  16. html链接路径分为哪几种,什么是url地址?
  17. Bentley 软件公司将以约 10.5 亿美元的价格收购全球领先的地球科学三维建模软件提供商 Seequent
  18. 安卓手机状态栏显示秒_免Root让安卓状态栏时间精确到秒
  19. 树莓派4B无线鼠标延迟解决办法
  20. 电磁学的三条右手法则

热门文章

  1. SwiftUI资源列表
  2. 算法:回溯十一 Subsets数组的子数组集合4种解法
  3. java面试常考_java面试常考题
  4. N!阶层末尾有多少0
  5. 梯度下降(一)--机器学习
  6. graphpad做饼图_超省钱的早餐攻略!这些边角料可别扔,多做一步变大餐!
  7. 【生信进阶练习1000days】day22-复习day1~day14的知识点
  8. Xencrypt:反病毒绕过工具
  9. java用this-gt;,java基础之十四-&gt;常用类
  10. android 7.1 灭屏,oppocolorosv7.1怎么设置息屏时钟