Dubbo点滴 SPI入门

spi(service providerinterface),是DUBBO功能强大的保障。核心支持类ExtensionLoader。

具体分析可以参照<Dubbo原理解析-Dubbo内核实现之基于SPI思想Dubbo内核实现>.

1.比较重要的注解

@SPI:扩展点接口的标识 :作用域在类上;

@Adaptive:为生成Adaptive实例提供参数,作用域在类或方法上;

@Activate:可以被框架中自动激活加载扩展,此Annotation用于配置扩展被自动激活加载条件。

1.1 测试对象代码

#1.声明SPI 默认为imp1
@SPI("impl1")
public interface SimpleExt {
    // 没有使用key的@Adaptive !
    @Adaptive
    String echo(URL url, String s);
    
    @Adaptive({"key1", "key2"})
    String yell(URL url, String s);

    // 无@Adaptive !
    String bang(URL url, int i);
}

//实现类1
public class SimpleExtImpl1 implements SimpleExt {
    public String echo(URL url, String s) {
        return "Ext1Impl1-echo";
    }
    
    public String yell(URL url, String s) {
        return "Ext1Impl1-yell";
    }
    
    public String bang(URL url, int i) {
        return "bang1";
    }
}
//实现类2
public class SimpleExtImpl2 implements SimpleExt {
    public String echo(URL url, String s) {
        return "Ext1Impl2-echo";
    }
    
    public String yell(URL url, String s) {
        return "Ext1Impl2-yell";
    }

    public String bang(URL url, int i) {
        return "bang2";
    }
    
}
//实现类3
public class SimpleExtImpl3 implements SimpleExt {
    public String echo(URL url, String s) {
        return "Ext1Impl3-echo";
    }
    
    public String yell(URL url, String s) {
        return "Ext1Impl3-yell";
    }

    public String bang(URL url, int i) {
        return "bang3";
    }
    
}

1.2 配置文件com.alibaba.dubbo.common.extensionloader.ext1.SimpleExt

位置要放在如下位置

private static final String SERVICES_DIRECTORY = "META-INF/services/";

private static final String DUBBO_DIRECTORY = "META-INF/dubbo/";

private static final String DUBBO_INTERNAL_DIRECTORY = DUBBO_DIRECTORY + "internal/";

具体内容如下

# Comment 1
impl1=com.alibaba.dubbo.common.extensionloader.ext1.impl.SimpleExtImpl1#Hello World
impl2=com.alibaba.dubbo.common.extensionloader.ext1.impl.SimpleExtImpl2  # Comment 2
   impl3=com.alibaba.dubbo.common.extensionloader.ext1.impl.SimpleExtImpl3 # with head space

定义3个实现。

1.4 测试

@Test
public void test_getDefaultExtension() throws Exception {
    SimpleExt ext = ExtensionLoader.getExtensionLoader(SimpleExt.class).getDefaultExtension();
    assertThat(ext, instanceOf(SimpleExtImpl1.class));
    
    String name = ExtensionLoader.getExtensionLoader(SimpleExt.class).getDefaultExtensionName();
    assertEquals("impl1", name);
}

由于@SPI("impl1"),定义了默认实现的名称为imp1.

@Test
public void test_getExtension() throws Exception {
    assertTrue(ExtensionLoader.getExtensionLoader(SimpleExt.class).getExtension("impl1") instanceof SimpleExtImpl1);
    assertTrue(ExtensionLoader.getExtensionLoader(SimpleExt.class).getExtension("impl2") instanceof SimpleExtImpl2);
}

getExtensionLoader(Class<T> type):根据类名,返回具体实现类。这些配置信息在META对应文件中配置。当然,也可以使用@Extention注解配置(只不过,这个注解已经废弃了)

@Test
public void test_getAdaptiveExtension_defaultAdaptiveKey() throws Exception {
    {
        SimpleExt ext = ExtensionLoader.getExtensionLoader(SimpleExt.class).getAdaptiveExtension();

        Map<String, String> map = new HashMap<String, String>();
        //没有指定具体parameters参数,所以选用默认实现,最后返回impl1
        URL url = new URL("p1", "1.2.3.4", 1010, "path1", map);
        //如果不设置默认的SPI实现类,则报异常
        //java.lang.IllegalStateException: Fail to get extension(com.alibaba.dubbo.common.extensionloader.ext1.SimpleExt) name from url(p1://1.2.3.4:1010/path1) use keys([simple.ext])
        String echo = ext.echo(url, "haha");
        assertEquals("Ext1Impl1-echo", echo);
    }

    {
        SimpleExt ext = ExtensionLoader.getExtensionLoader(SimpleExt.class).getAdaptiveExtension();

        Map<String, String> map = new HashMap<String, String>();
        map.put("simple.ext", "impl2");//手动在参数中配置impl2,参数为simple.ext
        URL url = new URL("p1", "1.2.3.4", 1010, "path1", map);

        String echo = ext.echo(url, "haha");
        assertEquals("Ext1Impl2-echo", echo);
    }
}

@Adaptive 测试

由于 yell方法声明了,@Adaptive({"key1", "key2"})

@Test
public void test_getAdaptiveExtension_customizeAdaptiveKey() throws Exception {
    SimpleExt ext = ExtensionLoader.getExtensionLoader(SimpleExt.class).getAdaptiveExtension();

    Map<String, String> map = new HashMap<String, String>();
    map.put("key2", "impl2");
    URL url = new URL("p1", "1.2.3.4", 1010, "path1", map);

    String echo = ext.yell(url, "haha");
    assertEquals("Ext1Impl2-yell", echo);

    url = url.addParameter("key1", "impl3"); // 注意: URL是值类型
    echo = ext.yell(url, "haha");
    assertEquals("Ext1Impl3-yell", echo);
}

如果参数不是key1,key2,即使参数值输入impl1,impl2也是无意义的。

由于bang方法,没有被@Adaptive 修饰,所以以下代码,会报异常

ExtensionLoader.getExtensionLoader(SimpleExt.class).getAdaptiveExtension().bang(..);

of interface com.alibaba.dubbo.common.extensionloader.ext1.SimpleExt is not adaptive method!

以上内容,是通过代码演练的方式,讲解了dubbo SPI机制的威力。
如果对底层实现感兴趣,可参看博客。

参照:Dubbo原理解析-Dubbo内核实现之基于SPI思想Dubbo内核实现

时间: 2024-10-10 05:00:24

Dubbo点滴 SPI入门的相关文章

Dubbo点滴(4)之暴露服务解析

Dubbo点滴(1) SPI入门 :了解下底层DUBBO底层扩展保证 Dubbo点滴(2)之集群容错:简单分析了DUBBO对高可用的保证手段 Dubbo点滴(3)之服务配置ServiceConfig:了解DUBBO相关元数据与对象 本节内容主要了解下DUBBO服务端的暴露服务过程. 吐下槽,这个Exporter命名个人感觉不好. Export,在DUBBO中既代表暴露过程,这儿是动作,对应export方法. 同时,Exporter接口,却代表着暴露的信息,比如URL. 总之,在研究过程中,对自己

Dubbo中SPI扩展机制解析

dubbo的SPI机制类似与Java的SPI,Java的SPI会一次性的实例化所有扩展点的实现,有点显得浪费资源. dubbo的扩展机制可以方便的获取某一个想要的扩展实现,每个实现都有自己的name,可以通过name找到具体的实现. 每个扩展点都有一个@Adaptive实例,用来注入到依赖这个扩展点的某些类中,运行时通过url参数去动态判断最终选择哪个Extension实例用. dubbo的SPI扩展机制增加了对扩展点自动装配(类似IOC)和自动包装(类似AOP)的支持. 标注了@Activat

Dubbo的SPI机制(1)

插件机制是Dubbo用于可插拔地扩展底层的一些实现而定制的一套机制,比如dubbo底层的RPC协议.注册中心的注册方式等等.具体的实现方式是参照了JDK的SPI思想,在dubbo的jar内部的/META-INF/dubbo/internal下会有许多以接口名命名的文件,如图: 这些文件正是用于扩展用途的,我们称之为SPI描述文件.每个文件就代表一种扩展,文件打开后,在文件中会以行为单位配置该扩展接口的具体实现类,每个扩展可以有多个实现,以key-value的形式进行配置.例如打开/META-IN

Dubbo点滴(5)之服务注册中心

首先DUBBO本质上是一款RPC框架,不可缺少的2个角色:服务提供者和服务消费者. 已经剖析了服务端暴露端口过程.本文简单说下注册中心. 1.注册中心是什么玩意 这是官网提供的图例 通过图例,可以看出消费者和提供者并不是直接通信的,中间有个第三者,就是注册中心.这种结构,可以实现消费者和提供者两者的依赖,和参数信息的集群化.所以这带来了几个问题. 服务注册 服务发现 服务订阅 服务通知 2. 服务暴露及服务注册过程 <Dubbo点滴(4)之暴露服务解析>已经剖析了dubbo协议具体打开网络端口

分布式的几件小事(五)dubbo的spi思想是什么

1.什么是SPI机制 SPI 全称为 Service Provider Interface,是一种服务发现机制. SPI 的本质是将接口实现类的全限定名配置在文件中,并由服务加载器读取配置文件,加载实现类.这样可以在运行时,动态为接口替换实现类. 正因此特性,我们可以很容易的通过 SPI 机制为我们的程序提供拓展功能.SPI 机制在第三方框架中也有所应用,比如jdbc. java定义了一套jdbc的接口,但是java是没有提供jdbc的实现类. 但是实际上项目跑的时候,要使用jdbc接口的哪些实

jdk和dubbo的SPI机制

前言:开闭原则一直是软件开发领域中所追求的,开闭原则中的"开"是指对于组件功能的扩展是开放的,是允许对其进行功能扩展的,“闭”,是指对于原有代码的修改是封闭的,即不应该修改原有的代码.对于一个高度集成化的.成熟.稳健的系统来讲,永远不是封闭.固守的,它需要向外提供一定的可扩展的能力,外部的实现类或者jar包都可以调用它.在面向对象的开发领域中,接口是对系统功能的高度抽象,因为SPI可谓是"应运而生",本篇博客就开始走进SPI,探究java自身的SPI和Dubbo的S

Dubbo的SPI机制与JDK机制的不同及原理分析

从今天开始,将会逐步介绍关于DUbbo的有关知识.首先先简单介绍一下DUbbo的整体概述. 概述 Dubbo是SOA(面向服务架构)服务治理方案的核心框架.用于分布式调用,其重点在于分布式的治理. 简单的来说,可以把它分为四个角色.服务提供方(Provider).服务消费方(Consumer).注册中心和监控中心.通过注册中心对服务进行注册和订阅,通过监控中心对服务进行监控. 核心功能 Remoting:远程通讯,提供对多种NIO框架抽象封装,包括"同步转异步"和"请求-响应

ZooKeeper分布式专题与Dubbo微服务入门

第1章 分布式系统概念与ZooKeeper简介对分布式系统以及ZooKeeper进行简介,使得大家对其有大致的了解1-1 zookeeper简介1-2 什么是分布式系统1-3 分布式系统的瓶颈以及zk的相关特性 第2章 ZooKeeper安装如何安装ZooKeeper以及对ZooKeeper最基本的数据模型进行剖析2-1 JDK的安装2-2 zookeeper下载.安装以及配置环境变量2-3 zookeeper文件夹主要目录介绍2-4 zookeeper配置文件介绍,运行zk 第3章 ZooKe

Dubbo教程:入门到实战

Dubbox简介 Dubbox 是一个分布式服务框架,其前身是阿里巴巴开源项目Dubbo ,被国内电商及互联网项目中使用,后期阿里巴巴停止了该项目的维护,当当网便在Dubbo基础上进行优化,并继续维护,为了与原有的Dubbo区分,故将其命名为Dubbox. Dubbox 致力于提供高性能和透明化的RPC远程服务调用方案,以及SOA服务治理方案.简单的说,dubbox就是个服务框架,如果没有分布式的需求,其实是不需要用的,只有在分布式的时候,才有dubbox这样的分布式服务框架的需求,并且本质上是