Java SPI加载机制

SPI加载机制

SPI(Service Provider Interface)是一种通过外界配置来加载具体代码内容的技术手段。SPI是JDK内置的一种服务提供发现机制,用于实现框架的扩展和组件替换。

在SPI中,框架提供一整套接口,使用者实现这些接口后,在classpath的目录META-INF/services/下创建以该接口命名的文件,并在该接口中写下实现类的全包名,SPI的加载机制则会加载该文件中类名对应的类。

下面是一个简单样例
首先定义一个接口

package cn.bobasyu.spi;

public interface ISpiTest {
    void test();
}

然后是这个接口的实现类

package cn.bobasyu.spi.impl;

import cn.bobasyu.spi.ISpiTest;

public class ASpiTestImpl implements ISpiTest {
    @Override
    public void test() {
        System.out.println("Hello A!");
    }
}

package cn.bobasyu.spi.impl;

import cn.bobasyu.spi.ISpiTest;

public class BSpiTestImpl implements ISpiTest {
    @Override
    public void test() {
        System.out.println("Hello B!");
    }
}

接着如前面所述的,在lasspath的目录META-INF/services/下创建以该接口命名的文件,并在该文件中写入两个实现类的名称

SPI

文件中的内容:

cn.bobasyu.spi.impl.ASpiTestImpl
cn.bobasyu.spi.impl.BSpiTestImpl

在运行时,使用ADK自带的ServiceLoader进行加载,即可读取文件中的类名并加载好对应的对象

    @Test
    public void spiLoadTest() {
        ServiceLoader<ISpiTest> serviceLoader = ServiceLoader.load(ISpiTest.class);
        for (ISpiTest spiTest : serviceLoader) {
            spiTest.test();
        }
    }

SPI在许多地方都有使用,比如在JDBC中,定义了java.sql.Driver接口,接下来针对每个数据库的具体实现需要在META-INF/services/中放入相应的文件,下面是mysql中的例子

Java SPI加载机制_第1张图片

文件中的内容:

Java SPI加载机制_第2张图片

使用SPI可以实现框架设计者和具体使用者间的解耦,在进行系统架构设计时,只关注抽象的部分,而框架的使用者则可以根据自己的需求进行自定义的扩展,其体现的是数据模式中的桥接模式,抽象部分与实现部分分离。

Java SPI加载机制_第3张图片

角色名 含义
抽象化(Abstraction)角色 抽象化给出的定义,并保存一个对实现化对象的引用
修正抽象化(RefinedAbstraction)角色 扩展抽象化角色,改变和修正父类对抽象化的定义
实现化(Implementor)角色 这个角色给出实现化角色的接口,但不给出具体的实现。必须指出的是,这个接口不一定和抽象化角色的接口定义相同,实际上,这两个接口可以非常不一样。实现化角色应当只给出底层操作,而抽象化角色应当只给出基于底层操作的更高一层的操作
具体实现化(ConcreteImplementor)角色 这个角色给出实现化角色接口的具体实现

你可能感兴趣的:(java)