高级Java程序员都必须要清楚的SPI服务扩展思想

本文深入解析了SPI(service provider interface)机制,介绍了SPI在JDK中的应用方式,包括如何使用ServiceLoader加载配置的实现类,以及在Dubbo框架中如何利用SPI思想进行服务扩展,自定义过滤器等。
部署运行你感兴趣的模型镜像

一、什么是SPI

SPI ,全称为 Service Provider Interface,是一种服务发现机制。JDK中的SPI是通过在ClassPath路径下的META-INF/services文件夹查找扩展文件,自动加载文件里所定义的类。

在小编的理解来,觉得它更是一种思想。即找到服务的接口, 美其名曰: 服务发现机制思想。很多开源框架都有借用这种思想,比如dubbo、jdbc。

二、SPI在JDK中如何使用

SPI在JDK中,我们可以使用 ServiceLoader 类进行使用。

1. 前提准备

public interface SpiService {
    String say();
}

两个实现类

public class ASpiServiceImpl implements SpiService {
    static {
        System.out.println("static init a");
    }

    {
        System.out.println("init a");
    }

    @Override
    public String say() {
        return "A";
    }
}
public class BSpiServiceImpl implements SpiService {
    static {
        System.out.println("static init b");
    }

    {
        System.out.println("init b");
    }
    @Override
    public String say() {
        return "B";
    }
}

2. 进行配置

在resources中创建META-INF/services目录

│  └── resources
│      └── META-INF
│          └── services
│              └── com.github.easylog.spi.SpiService

com.github.easylog.spi.SpiService文件内容

com.github.easylog.spi.impl.ASpiServiceImpl
com.github.easylog.spi.impl.BSpiServiceImpl

3. 使用

通过ServiceLoader类我们可以加载到所有配置的实现类,并对实现类进行处理。需要注意一点的是,看4使用注意。

public class SpiTester {
    public static void main(String[] args) {
        ServiceLoader<SpiService> spiServices = ServiceLoader.load(SpiService.class);
        Iterator<SpiService> iterator = spiServices.iterator();
        while (iterator.hasNext()) {
            SpiService next = iterator.next();
            System.out.println(next.say());
        }
    }
}

4. 使用注意

可以看下小编前面声明的两个实现类,都定义了静态代码块和非静态代码块。正常情况当这个字节码被加载,就会执行静态代码块里面的内容,但是实际运行时候却没有执行, 其实是有原因的。

可以看到第二个参数是false。即加载时候不进行初始化。

三、Dubbo中服务发现思想

服务发现这种思想的特点是: 代码不是硬编码的方式,而是可配置的。只要将要支持的实现类放到指定配置文件下面,就会自动被加载起来了。然后代码中只关心使用即可。我们可以利用这种思想来实现, 框架的扩展,比如前面说了。Dubbo会利用SPI的思想进行,加载用户自定义的过滤器。

这种思想特别适合做服务扩展。现在大多数开源框架中都会使用到这种思想。

1. 定义过滤器

@Activate(group = { Constants.PROVIDER })
public class ProviderHelloFilter implements Filter {
  
    @Override
    public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
        System.out.pringln("hello ok!");
        return invoker.invoke(invocation);
    }

}

2. 添加配置文件

META-INF/dubbo/Interal/com.alibaba.dubbo.rpc.Filter

默认支持的过滤器

利用SPI原理,我们自定义一个过滤器

3. 使用

其实API跟JDK中使用ServiceLoader的方式,非常类同。唯一不同的是Dubbo中是使用ExtensionLoader。因为dubbo中做了一些特殊的增强处理。比如在配置文件中支持自定义一个别名key。如上图hello就是key。通过getExtension(“hello”)就能获取指定的实现类。

public class SpiTester {
    public static void main(String[] args) throws Exception{
        ExtensionLoader<Filter> filterExtensionLoader = ExtensionLoader.getExtensionLoader(Filter.class);
        Set<String> supportedExtensions = filterExtensionLoader.getSupportedExtensions();
        System.out.println(supportedExtensions);
        //[accesslog, activelimit, cache...]
        Filter hello = filterExtensionLoader.getExtension("hello");
        //com.github.easylog.spi.ProviderHelloFilter@299a06ac
        System.out.println(hello);
    }
    
}

**那么这种思想你学会了吗? **

最后求关注,求订阅,谢谢你的阅读!

您可能感兴趣的与本文相关的镜像

ACE-Step

ACE-Step

音乐合成
ACE-Step

ACE-Step是由中国团队阶跃星辰(StepFun)与ACE Studio联手打造的开源音乐生成模型。 它拥有3.5B参数量,支持快速高质量生成、强可控性和易于拓展的特点。 最厉害的是,它可以生成多种语言的歌曲,包括但不限于中文、英文、日文等19种语言

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

西魏陶渊明

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值