阅读 90

Dubbo SPI

image.png 本文为拉勾课程的学习笔记

SPI简介

SPI 全称为 (Service Provider Interface) ,是JDK内置的一种服务提供发现机制。 目前有不少框架用它来做服务的扩展发现,简单来说,它就是一种动态替换发现的机制。使用SPI机制的优势是实现解耦,使得第三方服务模块的装配控制逻辑与调用者的业务代码分离。

JDK中的SPI

image.png Java中如果想要使用SPI功能,先提供标准服务接口,然后再提供相关接口实现和调用者。这样就可以通过SPI机制中约定好的信息进行查询相应的接口实现。

SPI遵循如下约定:

1、当服务提供者提供了接口的一种具体实现后,在META-INF/services目录下创建一个以“接口全 限定名”为命名的文件,内容为实现类的全限定名;

2、接口实现类所在的jar包放在主程序的classpath中;

3、主程序通过java.util.ServiceLoader动态装载实现模块,它通过扫描META-INF/services目录下的配置文件找到实现类的全限定名,把类加载到JVM;

4、SPI的实现类必须携带一个无参构造方法; 具体代码实现 项目的目录结构如下

image.png 首先创建一个新的项目 再创建一个接口定义的moudle 定义接口

public interface HelloService {
    String  sayHello();
}
复制代码

创建一个实现接口moudle 定义接口实现类

public class DogHelloService  implements HelloService {
    @Override
    public String sayHello() {
        return "wang wang";
    }
}

复制代码
public class HumanHelloService   implements HelloService {
    @Override
    public String sayHello() {
        return "hello 你好";
    }
}
复制代码

按照约定 在META-INF/services目录下创建一个以“接口全限定名”为命名的文件,内容为实现类的全限定名

image.png

主程序通过java.util.ServiceLoader动态装载实现模块,它通过扫描META-INF/services目录下的配置文件找到实现类的全限定名,把类加载到JVM

public class JavaSpiMain {
    public static void main(String[] args) {
        final ServiceLoader<HelloService> helloServices  = ServiceLoader.load(HelloService.class);
        for (HelloService helloService : helloServices){
            System.out.println(helloService.getClass().getName() + ":" + helloService.sayHello());
        }
    }
}
复制代码

Dubbo SPI

dubbo中大量的使用了SPI来作为扩展点,通过实现同一接口的前提下,可以进行定制自己的实现类。 比如比较常见的协议,负载均衡,都可以通过SPI的方式进行定制化,自己扩展。Dubbo中已经存在的所有已经实现好的扩展点。

dubbo已经实现好的扩展点

image.png

dubbo中使用扩展点的方式 创建一个项目,目录结构如下

image.png 定义接口

@SPI
public interface HelloService {
    String  sayHello();
}
复制代码

定义实现类

public class DogHelloService implements HelloService{
    @Override
    public String sayHello() {
        return "wang wang";
    }
}
复制代码
public class HumanHelloService implements HelloService{
    @Override
    public String sayHello() {
        return "hello 你好";
    }
}
复制代码

创建一个META-INF.dubbo文件夹,创建以“接口全限定名”为命名的文件,内容的key为实现类的别名,value为实现类的全限定类名。 image.png

使用

public class  DubboSpiMain {
    public static void main(String[] args) {
        // 获取扩展加载器
        ExtensionLoader<HelloService>  extensionLoader  = ExtensionLoader.getExtensionLoader(HelloService.class);
        // 遍历所有的支持的扩展点 META-INF.dubbo
        Set<String>  extensions = extensionLoader.getSupportedExtensions();
        for (String extension : extensions){
            String result = extensionLoader.getExtension(extension).sayHello();
            System.out.println(result);
        }

    }
}
复制代码

运行结果

image.png

Dubbo SPI中的Adaptive功能

Dubbo中的Adaptive功能,主要解决的问题是如何动态的选择具体的扩展点。通过 getAdaptiveExtension 统一对指定接口对应的所有扩展点进行封装,通过URL的方式对扩展点来进行动态选择。 (dubbo中所有的注册信息都是通过URL的形式进行处理的。)这里同样采用相同的方式进行实现。 基于上面的代码进行修改 在接口中增加一个入参为URL的方法

@SPI("human") // 注解中的值表示默认实现类的别名,就是指定url的情况下 默认实现HumanHelloService 这个实现类
public interface HelloService {
    String  sayHello();
    @Adaptive
    String  sayHello(URL  url);
}
复制代码

实现类

public class DogHelloService implements HelloService{
    @Override
    public String sayHello() {
        return "wang wang";
    }

    @Override
    public String sayHello(URL url) {
        return "wang url";
    }
}
复制代码
public class HumanHelloService implements HelloService{
    @Override
    public String sayHello() {
        return "hello 你好";
    }

    @Override
    public String sayHello(URL url) {
        return  "hello url";
    }
}

复制代码

使用

public class DubboAdaptiveMain {
    public static void main(String[] args) {
        URL   url  = URL.valueOf("test://localhost/hello?hello.service=dog");
        HelloService  adaptiveExtension = ExtensionLoader.getExtensionLoader(HelloService.class).getAdaptiveExtension();
        String  msg = adaptiveExtension.sayHello(url);
        System.out.println(msg);
    }
}
复制代码

上面代码 URL url = URL.valueOf("test://localhost/hello?hello.service=dog"); 中的参数,?前面的可以随便指定,因为这只是一个demo,?后面的hello.service 为接口HelloService的名字,= 后面的内容为文件中定义的key。

运行结果

image.png

如果不指定实现类的话,则实现默认的实现类

image.png

image.png

文章分类
后端
文章标签