SPI机制

1、 Java SPI

Java SPI(Service Provider Interface)是一种在 Java 中实现插件化架构的机制。
SPI 允许开发者定义服务接口,然后实现这些服务接口的不同提供者,使得应用程序在不修改源代码的情况下可以动态地加载、使用不同的服务提供者。
这种机制非常适合于框架和库,因为它允许开发者为特定的功能提供多个实现,而应用程序可以在运行时选择合适的实现。
Java中SPI机制主要思想是将装配的控制权移到程序之外,在模块化设计中这个机制尤其重要,其核心思想就是 解耦

当服务的提供者提供了一种接口的实现之后,需要在**classpath下的META-INF/services/**目录里创建一个以服务接口命名的文件,这个文件里的内容就是这个接口的具体的实现类。当其他的程序需要这个服务的时候,就可以通过查找这个jar包(一般都是以jar包做依赖)的META-INF/services/中的配置文件,配置文件中有接口的具体实现类名,可以根据这个类名进行加载实例化,就可以使用该服务了。JDK中查找服务的实现的工具类是:java.util.ServiceLoader

java SPI实现示例

以下是一个简单的 Java SPI 示例,假设我们有一个服务接口 MyService,以及两个不同的实现提供者 MyServiceImpl1 和 MyServiceImpl2。

1、创建服务接口 MyService

public interface MyService {
    void doSomething();
}

2、创建两个实现提供者,MyServiceImpl1 和 MyServiceImpl2

public class MyServiceImpl1 implements MyService {
    @Override
    public void doSomething() {
        System.out.println("MyServiceImpl1 is doing something.");
    }
}

public class MyServiceImpl2 implements MyService {
    @Override
    public void doSomething() {
        System.out.println("MyServiceImpl2 is doing something.");
    }
}

3、创建 META-INF/services 目录,用于存放服务提供者配置文件。

4、在 META-INF/services 目录下创建一个名为 限定类名MyService 的文件,其中包含服务提供者的类名:

在这里插入图片描述在这里插入图片描述

5、创建应用程序代码,使用 SPI 加载并使用服务提供者

package com.lf.java.basic.spi;

import java.util.ServiceLoader;

public class ServiceLoaderTest {
    public static void main(String[] args) {
        ServiceLoader<MyService> serviceLoader = ServiceLoader.load(MyService.class);
        for (MyService service : serviceLoader) {
            service.doSomething();
        }
    }
}

运行结果:

在这里插入图片描述
在这个示例中,ServiceLoader 用于加载 MyService 的实现提供者,并调用它们的 doSomething 方法。应用程序不需要知道有哪些具体实现,它们会在运行时动态加载。

确保在编译和运行时正确设置类路径,以便能够找到服务提供者的实现类。这个示例演示了 Java SPI 的基本用法,可以用于更复杂的插件化架构,允许动态地添加、删除或替换服务提供者。

2、Dubbo SPI

Dubbo 的 SPI(Service Provider Interface)机制是其扩展功能的基础,它允许在不修改源码的情况下,通过配置文件或代码注册并加载实现类。

1、Dubbo SPI 的工作原理:

1、扩展接口定义: Dubbo 的各种扩展点(如 Filter、Cluster、LoadBalance)都有对应的接口,定义了可扩展的方法。

2、SPI 配置文件: Dubbo 在 META-INF/dubbo 目录下提供了对应的配置文件,用于声明接口的实现类。比如 META-INF/dubbo/org.apache.dubbo.rpc.Filter 是用于声明 Filter 的实现类。

3、接口实现类: 开发者实现扩展接口的实现类,并在 META-INF/dubbo 下的配置文件中进行注册。

4、SPI 加载机制: Dubbo 在初始化时会根据配置文件加载对应接口的实现类。在使用时,通过接口的工厂方法获取具体的实现类实例。

在 Dubbo 中,Filter、Cluster 和 LoadBalance 都是 Dubbo 中的重要组件,用于处理不同方面的任务。

2、Dubbo SPI的Filter实现示例

Filter 在 Dubbo 中类似于拦截器,用于拦截服务的调用和响应过程。Dubbo 提供了多种 Filter,比如服务调用前后的日志记录、异常处理、权限控制等。

开发者可以实现自定义的 Filter,自定义处理逻辑,并通过配置的方式将其添加到 Dubbo 的调用链中,对服务的调用进行拦截、修改和补充。

1、定义 Filter 接口:

package org.apache.dubbo.rpc;

public interface Filter {
    Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException;
}

2、编写实现类 MyFilter:

package com.example.dubbo;

import org.apache.dubbo.common.extension.SPI;
import org.apache.dubbo.rpc.Filter;
import org.apache.dubbo.rpc.Invocation;
import org.apache.dubbo.rpc.Invoker;
import org.apache.dubbo.rpc.Result;
import org.apache.dubbo.rpc.RpcException;

@SPI
public class MyFilter implements Filter {
    @Override
    public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
        // 实现自定义 Filter 的逻辑
        return invoker.invoke(invocation);
    }
}

3、配置文件声明 MyFilter:

在 META-INF/dubbo 目录下创建 org.apache.dubbo.rpc.Filter 文件,并添加:

myfilter=com.example.dubbo.MyFilter

4、使用 MyFilter:

在 Dubbo 注解中使用该 Filter:

@DubboService(filter = "myfilter")
public class HelloServiceImpl implements HelloService {
    // 实现服务方法
}

Dubbo 在启动时会自动加载
META-INF/dubbo/org.apache.dubbo.rpc.Filter 文件中声明的 Filter 实现类,使得开发者可以在代码中直接使用自定义的 Filter。

@DubboService(filter = “myfilter”) 注解用于标记 HelloServiceImpl 这个 Dubbo 服务实现类,并通过 filter = “myfilter” 指定了使用名为 myfilter 的 Dubbo Filter。这个过滤器将会在 Dubbo 的服务调用链中生效。

Dubbo Filter 可以被用于多种场景,比如实现对服务的统一日志记录、权限控制、异常处理等。当 Dubbo 服务调用时,注册了指定的 Filter(在这个例子中是 myfilter),Dubbo 框架会在调用前后对服务进行拦截,执行 Filter 中定义的逻辑

这就是 Dubbo SPI 机制的基本工作原理。

3、Dubbo SPI的Cluster实现示例

Cluster 在 Dubbo 中用于处理服务调用的集群容错。Dubbo 支持多种集群容错策略,比如 Failover、Failfast、Failsafe 等。

开发者可以根据需要自定义 Cluster,实现特定的容错策略,比如自定义重试逻辑、失败处理方式等。Cluster 负责将多个 Invoker(服务提供者)组合成一个,提供给调用者使用。

1、实现自定义 Cluster:

public class MyCluster implements Cluster {
    @Override
    public <T> Invoker<T> join(Directory<T> directory) throws RpcException {
        // 自定义 Cluster 的逻辑
        return null; // 返回 Invoker 实例
    }
}

2、在配置文件中配置该 Cluster:

在 META-INF/dubbo 目录下的 org.apache.dubbo.rpc.Cluster 文件中添加配置:

mycluster=com.example.MyCluster

3、在 Dubbo 注解中使用该自定义 Cluster:

@DubboService(cluster = "mycluster")
public class HelloServiceImpl implements HelloService {
    // 实现服务方法
}

4、Dubbo SPI的LoadBalance实现示例

LoadBalance 是 Dubbo 中负责服务调用时的负载均衡策略的组件。Dubbo 提供了多种负载均衡策略,如 RoundRobin、Random、LeastActive 等。

LoadBalance 负责在多个服务提供者中选择合适的节点来进行调用,使得请求能够分布到各个节点,实现负载均衡。开发者可以自定义负载均衡策略,根据实际业务需求选择节点。

1、实现扩展接口: 首先,你需要实现 Dubbo 扩展接口,比如 Filter、Cluster、LoadBalance 等 Dubbo 内置的扩展接口。比如,你可以实现一个自定义的负载均衡策略

public class MyLoadBalance implements LoadBalance {
    // 实现 LoadBalance 接口的方法
}

2、配置扩展点: 在 META-INF/dubbo 目录下创建对应的配置文件,比如在 META-INF/dubbo 目录下创建 org.apache.dubbo.rpc.LoadBalance 文件,将自定义的实现类配置到该文件中。

myloadbalance=com.example.MyLoadBalance

3、使用自定义组件: 接下来,在 Dubbo 的 XML 配置文件或者注解配置中,可以使用自定义的组件,比如在 Reference 或 Service 注解中指定使用你自定义的负载均衡策略。

@DubboReference(loadbalance = "myloadbalance")
private HelloService helloService;

3、Java SPI Vs DubboSPI

相似之处

  1. 服务发现机制: 都是一种服务发现和加载机制,允许通过配置或其他方式注册和加载实现类。

    接口与实现分离: 都支持接口与实现分离的方式,使得接口的实现可以独立变更、扩展或替换。

    声明式加载: 都支持声明式的方式注册实现类,通过配置文件或注解等方式指定实现类

不同之处

1、实现机制:

Dubbo SPI: Dubbo SPI 是 Dubbo 框架自己实现的一套服务扩展机制,对 Java SPI 进行了一定程度的封装和优化,提供了更灵活、功能更强大的扩展机制。Dubbo SPI 除了通过配置文件声明,还支持通过注解和代码方式进行扩展加载。

Java SPI: Java SPI 是 JDK 自带的一种服务扩展机制,通过在 META-INF/services 目录下提供接口全限定名为文件名的配置文件,声明接口的实现类。

2、灵活性:

Dubbo SPI: Dubbo SPI 提供了更丰富的配置和加载方式,支持注解、配置文件和代码方式进行实现类的注册和加载,具有更高的灵活性。可以指定加载实现类,防止一次加载所有实现类。

Java SPI: Java SPI 只支持配置文件的方式,缺乏灵活性,加载实现类时只能通过 ServiceLoader 进行,而且会加载所有实现类,性能差。

3、扩展性:

Dubbo SPI: Dubbo SPI 为了更好地满足 Dubbo 框架自身的需求,提供了更多的扩展点和机制,比如 Filter、Cluster、LoadBalance 等扩展点,使得扩展更为灵活和方便。

Java SPI: Java SPI 对于扩展点较少,一般用于标准的 JDK 接口扩展,使用场景相对较少。

总的来说,Dubbo SPI 在 Java 原生的 SPI 机制基础上做了进一步的封装和扩展,提供了更多的灵活性和功能性,适用于更复杂的应用场景和更多的扩展点。
而 Java SPI 则是 JDK 自带的一种简单的服务发现机制,用于简单的接口和实现类的加载,功能较为有限。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值