JDK SPI机制

原创
2020/03/29 20:12
阅读数 55

1 概述

SPI(Service Provider Interface)是指一种服务发现机制,为某个特定的接口寻找服务的实现。在大规模的软件开发中经常采用这样的机制,实现模块之间基于接口编程,隐藏其实现细节,不同的服务提供商进行扩展实现,最终实现无需修改代码即可调用,完全无代码入侵,如在JDBC 4.0之后支持SPI的方式加载驱动程序。

2 使用场景

如common-logging 中只是提供了日志操作的相关接口,而具体实现交由其他服务提供者自己去实现,再如JDBC提供了抽象的驱动操作接口,具体实现交由其他服务提供商自己去实现,4.0之前需要手动代码中配置驱动类,但在4.0之后支持SPI的方式加载驱动程序。

3 如何使用

下面我们通过一个简单的案例代码来演示SPI的具体使用,如我们提供一个抽象的Protocol协议接口,但具体实现交由子系统自己实现

3.1 外部包中Protocol协议接口

public interface Protocol {

    String defaultName();
}

3.2 外部包中提供ProtocolFactory

用来打印其他子系统接口实现的具体协议名称,JDK中提供通过ServiceLoader来加载接口的具体实现类

public class ProtocolFactory {

    public static void outProtocolName() {
        ServiceLoader<Protocol> protocols = ServiceLoader.load(Protocol.class);
        for (Protocol protocol : protocols) {
            System.out.println("协议名称:" + protocol.defaultName());
        }
    }
}

3.3 子系统中提供具体接口实现

子系统中依赖包含Protocol接口的外部包,然后分别提供HttpProtocol和RpcProtocol具体实现类

public class HttpProtocol implements Protocol {
    @Override
    public String defaultName() {
        return "HttpProtocol";
    }
}
public class RpcProtocol implements Protocol {
    @Override
    public String defaultName() {
        return "RpcProtocol";
    }
}

3.4 配置接口实现类

在子系统模块中的resources目录下新建META-INF\services目录,然后在services目录下新建com.os.china.spi.Protocol文件,文件中添加具体实现类的全路径名称

com.os.china.spi.HttpProtocol
com.os.china.spi.RpcProtocol

3.5 测试

public class MainBootstrap {
    public static void main(String[] args) {
        ProtocolFactory.outProtocolName();
    }
}

执行上面Main函数可以看到输出

协议名称:HttpProtocol
协议名称:RpcProtocol

3.6 AutoService

通过以上简单案例来演示SPI的具体使用方式,通过接口与实现分离的方式可以达到灵活扩展的目的,不足的是需要手动创建Protocol接口服务的配置文件,这里推荐可以通过Google提供的auto-service包中的@AutoService注解类自动创建该配置文件,十分便捷

3.6.1 引入AutoService包

<dependency>
     <groupId>com.google.auto.service</groupId>
     <artifactId>auto-service</artifactId>
     <version>1.0-rc4</version>
</dependency>

3.6.2 实现类标注@AutoService(Protocol.class)注解

分别在HttpProtocol与RpcProtocol实现类上标注@AutoService(Protocol.class)注解

@AutoService(Protocol.class)
public class HttpProtocol implements Protocol {
    @Override
    public String defaultName() {
        return "HttpProtocol";
    }
}
@AutoService(Protocol.class)
public class RpcProtocol implements Protocol {
    @Override
    public String defaultName() {
        return "RpcProtocol";
    }
}

然后启动测试类发现AutoService会自动帮我们创建services配置文件

4 总结

通过以上简单案例来演示SPI的具体使用方式,通过接口与实现分离的方式可以达到灵活扩展的目的,并且介绍了Google提供的AutoService来辅助实现SPI更加便捷。

 

展开阅读全文
加载中
点击引领话题📣 发布并加入讨论🔥
0 评论
0 收藏
0
分享
返回顶部
顶部