Java的SPI机制是什么

2024-08-10 18:58:59 浏览数 (2)

Java的SPI机制是什么

一、介绍

大家有没有遇到过这么一个神奇的现象,在Java中,我们引入了什么日志就会用到什么日志,

比如说,我引入了logback,那么日志打印就会使用logback

引入了log4j,那么就会使用log4j

演示就不进行了,但这是怎么做到的呢?

实际上,它正是使用了JavaSPI机制

SPI机制,是Service Provider Interface的缩写,字面意思就是服务提供者的接口。

详细描述就是,一个框架提供暴露出一个接口,交给外部第三方去完成具体的实现。框架不需要关系是谁,哪些类实现了这个接口,只需要调用这个接口的方法,完成功能即可。

按照这么说,日志框架应该就是这个样子。有一个接口提供出去,不同的框架去实现这个接口,到时候maven依赖引入,就自动的加载成功。

好的,那下面我们来自己手动写一个SPI的代码,加深一点印象

二、代码

1)接口及扩展

同介绍中说的,我们先提供一个接口,我把它放在learn-spi-core工程下边,这个接口里面就一个方法

代码语言:javascript复制
package com.banmoon;
​
/**
 * SPI测试接口
 *
 * @author banmoon
 * @date 2024/08/09 13:59:38
 */
public interface BaseExecutor {
​
    /**
     * 执行
     */
    void execute();
​
}

那么,我另开一个工程,learn-spi-extend-a,去写一个实现类

代码语言:javascript复制
package com.banmoon;
​
/**
 * @author banmoon
 * @date 2024/08/09 14:05:07
 */
public class ExtendExecutorA implements BaseExecutor  {
    @Override
    public void execute() {
        System.out.println("扩展A");
    }
}

十分简单,就打印了一句话

关键来了,实现SPI机制的关键就是要在resources中添加这么一个文件夹,META-INF.services

里面新增这么一个文件com.banmoon.BaseExecutor,文件名正好就是上面提供的接口权限名,里面放上自己实现类的权限名

代码语言:javascript复制
com.banmoon.ExtendExecutorA

2)测试一下

直接再开一个工程learn-spi-mainmaven引入相关依赖

代码语言:javascript复制
<dependencies>
    <dependency>
        <groupId>com.banmoon</groupId>
        <artifactId>learn-spi-core</artifactId>
        <version>1.0-SNAPSHOT</version>
    </dependency>
    <dependency>
        <groupId>com.banmoon</groupId>
        <artifactId>learn-spi-extend-a</artifactId>
        <version>1.0-SNAPSHOT</version>
    </dependency>
</dependencies>

就在这个工程下面,编写main方法

代码语言:javascript复制
package com.banmoon;
​
import java.util.ServiceLoader;
​
/**
 * @author banmoon
 * @date 2024/08/09 15:41:11
 */
public class Main {
​
    public static void main(String[] args) {
        ServiceLoader<BaseExecutor> load = ServiceLoader.load(BaseExecutor.class);
        for (BaseExecutor executor : load) {
            executor.execute();
        }
    }
​
}

运行查看效果,可以发现明明没有实例化的动作,但确实有打印输出

三、再次扩展

那么本次,我们再添加一个工程learn-spi-extend-b,同样的实现

代码语言:javascript复制
package com.banmoon;
​
/**
 * @author banmoon
 * @date 2024/08/09 14:05:07
 */
public class ExtendExecutorB implements BaseExecutor  {
    @Override
    public void execute() {
        System.out.println("扩展B");
    }
}

同样的在META-INF.services加入文件

测试之前,我们将maven依赖加入上去

代码语言:javascript复制
<dependencies>
    <dependency>
        <groupId>com.banmoon</groupId>
        <artifactId>learn-spi-core</artifactId>
        <version>1.0-SNAPSHOT</version>
    </dependency>
    <dependency>
        <groupId>com.banmoon</groupId>
        <artifactId>learn-spi-extend-a</artifactId>
        <version>1.0-SNAPSHOT</version>
    </dependency>
    <dependency>
        <groupId>com.banmoon</groupId>
        <artifactId>learn-spi-extend-b</artifactId>
        <version>1.0-SNAPSHOT</version>
    </dependency>
</dependencies>

main方法代码不用动,执行运行,可以看到两个都出来了

四、最后

代码比较简单,但就是这样的一个机制,可以完成框架神奇一般的功能

附上本次,项目的工程结构图

0 人点赞