JavaSPI机制
SPI是什么?
全成Service provider interface
,中文意思是服务提供发现。它是JDK内置的一种服务提供发现机制
在微服务中也有服务发现
,但是这两个并不是一个东西
Java SPI 实际上是“基于接口的编程+策略模式+配置文件”组合实现的动态加载机制
这就是典型的面向接口编程。
SPI实践(需要遵守SPI约定)
JDK中提供了一个工具类java.util.ServiceLoader
,查找服务实现。
可以看到他里面定义了一个常量PREFIX="META-INF/services/"
,它会根据这个前缀去查找jar包的META-INF/services/中的配置文件。配置文件中有接口的实现类全限定类名,可以根据类名进行加载实例化,就可以使用该服务了。
可以看到
Service模块
- 定义接口
1 | package cn.this52.service; |
AliPay实现模块
- 定义实现类,引入Service jar,实现PayService接口
1 | package cn.this52.service.impl; |
1 | <dependency> |
- 在resources目录下创建META-INF/services文件夹,创建一个以接口全限定类名命名的文件,文件内容为实现类全限定类名
1 | cn.this52.service.impl.AliPay |
测试模块
1 | package cn.this52.main; |
成功调用到服务!
SPI约定
当服务提供者提供了接口的一种具体实现后,在jar包的META-INF/services目录下创建一个以“接口全限定名”为命名的文件,内容为实现类的全限定名;
接口实现类所在的jar包放在主程序的classpath中;
主程序通过java.util.ServiceLoder动态装载实现模块,它通过扫描META-INF/services目录下的配置文件找到实现类的全限定名,把类加载到JVM;
SPI的实现类必须携带一个不带参数的构造方法;
SPI具体应用
DriverManager
DriverManager是jdbc里管理和注册不同数据库driver的工具类。针对一个数据库,可能会存在着不同的数据库驱动实现。
Java定义了java.sql.Driver接口,并没有具体实现,都是由不同厂商来提供的
在JDBC4.0后连接数据库不需要再用Class.forName("com.mysql.jdbc.Driver")
来加载驱动了,就是使用了Java的SPI扩展机制来实现的
在mysql-connector-java 5.1.49
jar中,META-INF/services目录下会有一个名字为java.sql.Driver的文件:
文件内容,跟我们刚刚实践的是一样的
1 | com.mysql.jdbc.Driver |
看下Mysql Driver实现
可以看到它实现了java.sql.Driver
接口,然后看下static静态块的DriverManage注册驱动
可以看到static静态块中有个loadInitialDrivers()
方法
可以看到它使用的也是ServiceLoader类,遍历所有的jar下META-INF/services/中的以java.sql.Driver命名的文件里面的内容,并封装到一起,然后分割,通过Class.forName来加载类。就不需要我们来注册了。