目录
一、什么是SPI机制
二、SPI机制的作用
三、SPI的一些应用
四、 例子
SPI因为service provider interface 意为:服务提供者的接口
就是为服务提供者提供的接口,就是设计一套接口规范,然后不同的服务提供者去进行相应的实现
这个SPI机制依赖于Java库中的ServiceLoad类加载实现类才能实现这样一种机制
过程:
1. 需要提供一个接口
2. 服务提供者去实现接口,就有会对应的实现类
上面这样也能直接用,但是多个实现就有多个jar包,其实服务调用方和服务的提供者还是存在一定的耦合的,我想换一种,那里就要另外编写一种,存在耦合
ServiceLoad就可以加载出所有的实现类,得到实现类的集合。
说一下这个使用的步骤:
1.在接口的提供者这一方项目中的resource目录下面,创建好一个和接口全类名一模一样的文件,然后在这个文件中写好实现类的全类名
2. 然后就能使用ServiceLoad加载出文件中写的这些实现类,获取到这些实现类了,在接口的提供者实际上就能真正的使用自己写的实现类了,因为我仅仅实现接口有一个接口实现类是不行的,其实就是接口提供者这边其实是导入了那套接口规范,那套结构中其实是里面使用到了ServiceLoad去加载类的,然后再完成操作。其实实现类只是工具,具体怎样使用这个工具由定义接口规范的人说的,现在接口提供者这一方已经有了实现类了,有了接口规范了(其实并不是真正的是接口规范,而是说操作接口方法的一段代码逻辑)。现在的问题就是说到底怎样才能让真正的使用到这些实现类中的具体实现。当然不能直接new的方式,这样就写死了,就只能一种实现类。那有什么办法,就是说不通过new的方式,然后也能拿到实现类,并且这里是可以拿到所有的实现类对象,只有这样,才真正的解耦合。
其实:
接口规范这一边要干的活:
1. 定义接口 其实就是定义好接口中的方法 想清楚到底要一些什么样的方法,大致是想要干什么?
2. 定义操作接口方法的一套流程 通过这个流程就能真正的干活
服务提供者这一方需要干的活:
其实服务提供者的这一边它需要导入 这一套接口规范以及这一套方法流程 其实就是得到接口规范的这一方的全部 所以通常来说接口提供者这一方,需要导入接口规范的jar包
1. 写实现类
2. 项目中的resource目录下面,创建好一个和接口全类名一模一样的文件,然后在这个文件中写好实现类的全类名
只要这样 就可以通过ServiceLoad感知到这些实现类 将“实现类”填充到那个方法流程框架中
然后就能够真正的正常执行那一套流程了
因此我们现在只需要将服务提供者打一个jar包,然后我们调用方的这一边就导入这个jar包就能使用了 就能使用那套流程了
就是解耦合
它的强大之处在于我代码真的可以完完全全的写死,完完全全不需要任何的改动,就能直接使用到接口提供者给我们实现的方法
jdbc 也是一个接口规范一方定义好一写接口 java.sql.Driver 写好这个里面的方法
Connection connect(String url, java.util.Properties info)
throws SQLException;
java.sql.* 这个包下定义了接口 Connnct PrepareStatement ResultSet
然后不同的数据库厂商就根据这些接口写好对应的实现类
在之前还没有ServiceLoad这个类 所以它能做的就只能实现好那些接口 但是呢 其实还是不能直接用,那怎样才能用?那就需要服务调用 方完成加载驱动这一步的 只有完成了这一步相当于才真正的将实现类导入过来了
现在有了ServiceLoad这个类,就可以调用它的load方法,然后就能自动的加载这个接口下面的实现类 所以现在数据库厂商那边就可以直接注册这个实现类了 通过规定的步骤 就是写一个文件
既然现在数据库厂商那边 相当于都把事情做好了,因此我们调用方这边就可以不需要再去完成注册驱动的这一步了,这一步可以省略了 这是JDBC4.0之后支持的
关键:
ServiceLoader s = ServiceLoader.load(Driver.class);
ServiceLoader s = ServiceLoader.load(Connection.class);
.....
然后在数据库服务器厂商那边在项目的resouces目录下面写好:
一个 名为java.sql.Driver的文件 然后里面写Driver实现类的全类名
......
另外还有日志框架也是利用SPI机制
我们现在需要使用一个内容搜索接口,搜索的实现可能是基于文件系统的搜索,也可能是基于数据库的搜索。
public interface Search {
public List searchDoc(String keyword);
}
public class FileSearch implements Search{
@Override
public List searchDoc(String keyword) {
System.out.println("文件搜索 "+keyword);
return null;
}
}
public class DatabaseSearch implements Search{
@Override
public List searchDoc(String keyword) {
System.out.println("数据搜索 "+keyword);
return null;
}
}
com.cainiao.ys.spi.learn.Search
,里面加上我们需要用到的实现类com.cainiao.ys.spi.learn.FileSearch
public class TestCase {
public static void main(String[] args) {
ServiceLoader s = ServiceLoader.load(Search.class);
Iterator iterator = s.iterator();
while (iterator.hasNext()) {
Search search = iterator.next();
search.searchDoc("hello world");
}
}
}