Java SPI的原理和实践

SPI,全称是Service Provider Interface ,是java6引入的一种基于ClassLoader来发现并加载服务的机制,一个标准的SPI由3个组件构成,分别是:

1,Service, 即自定义的接口或抽象类

2,Service Provider,即Service接口的实现类

3,ServiceLoader,即java.util.ServiceLoader类,负责加载Service Provider

一,SPI示例:

1,定义一个接口,即Service

package com.xx;

public interface MyInterface {
}

2,定义一个或多个实现类,即Service Provider

package com.xx;

public class MyInterfaceImplA implements MyInterface{
}
package com.xx;

public class MyInterfaceImplB implements MyInterface{
}

3,建立配置文件

如下,如果是非maven项目,配置文件放在 src/META-INF/services目录下;

如果是maven项目,配置文件放在 resources/META-INF/services目录下;

文件名是接口的全限定名,文件内容是实现类的全限定名,如果有多个实现类每个占一行

4, 获取实现类

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

输出结果如下:

可以看到已经创建了2个实现类的实例。

二, SPI的三大规范要素:

1,配置文件的规范

1.1,配置文件路径:必须在工程或JAR包中的META-INF/services目录下

1.2,配置文件名称:Service接口的全限定名

1.3,配置文件内容:Service实现类(即Service Provider类)的全限定名,如果有多个实现类,每个实现类在文件中独占一行

2,Service Provider类必须有无参的构造方法

3,保证能加载到配置文件和Service Provider类

3.1 将Service Provider类的jar包放到classpath中

3.2 将jar包安装到jre的扩展目录中

3.3 自定义一个ClassLoader

三,SPI的作用?

我的理解:提供了一种约定俗成的方式,能根据接口类名找它的实现类并创建实现类对象,可用于实现各种插件或者灵活替换框架所使用的组件,也可减少框架使用者对框架的配置。

四,SPI的优点?

面向接口编程+配置文件+反射技术,优雅的实现模块之间的解耦

五,SPI应用场景

JDBC 、SLF4J、Servlet容器初始化、另外springboot的自动配置借鉴了SPI的思想。

5.1 JDBC中SPI的使用

在SPI出现之前,使用Class.forName加载数据库驱动:

程序员需要记住不同数据库的驱动类名称,通过SPI机制就不需要记住了:

因为JDBC驱动接口的全限定名是java.sql.Driver,各个数据库厂商都是实现此接口,

因此各厂商可以在自己的jar包META-INF/services目录下创建一个java.sql.Driver的文件,里面写上自己的实现类名称,这样,程序员在使用数据库驱动jar包时,只需引入这个jar包即可,不用关心其实现类是哪个,程序启动时会自动创建java.sql.Driver文件中的类。

下图是mysql的驱动jar解压之后的内容,里面确实有java.sql.Driver文件,如下:

5.2 springboot借鉴SPI思想产生了spring Factories 机制,实现了自动配置:

spring Factories 机制的配置文件叫 spring.factories(类似SPI的配置文件),放置在META-INF下,文件内容的格式是

接口全限定名 = 实现类全限定名1,实现类全限定名2

例如springboot自动加载mybatis原理如下:

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值