- 苏格团队
- 做者:Handsome
SPI与咱们熟知的API名字上有点类似,SPI被称为服务提供接口,API称为应用程序接口,二者的区别大体能够这样来对比。 假设有客户方和服务方,彼此经过约定的接口对接。java
咱们平时最多见的SPI服务就是JDBC。经过统一的JDBC规范,客户方能够本身实现各类数据源。试想一下,假设开发者想将数据源从Mysql切换到Oracle,若是没有使用JDBC,切换的过程就须要耗费巨大的人力成本。mysql
如何解决上述的数据源切换问题,这里须要说一下依赖倒置原则。git
JDBC链接Mysqlgithub
Class.forName("com.mysql.jdbc.Driver");
Connection conn = DriverManager.getConnection(
"jdbc:mysql://localhost:3306/test", "root", "123456");
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery("select * from Users");
复制代码
下面本身实现一个简易版的JDBC程序。 驱动管理程序,负责加载各SPI服务,用一个Map保存全部加载过的驱动程序,key为SPI服务自定义的名称。在调用connection时,只要url中的前缀为驱动名,则使用该驱动建立链接。sql
/** * 驱动管理,负责加载各客户方提供的数据源服务/ */
public class MyDriverManager {
/** * 全部注册的数据源链接服务/ */
private static final Map<String, MyDriver> registerDriver = new HashMap<String, MyDriver>();
public static void registerDriver(String name, MyDriver driver) {
registerDriver.put(name, driver);
}
public static MyConnection getConnection(String url) {
for (String key : registerDriver.keySet()) {
if (url.startsWith(key)) {
return registerDriver.get(key).getConnection(url);
}
}
throw new RuntimeException("no such provider");
}
}
复制代码
定义驱动接口bash
public interface MyDriver {
/** * 获取链接 */
MyConnection getConnection(String url);
}
复制代码
客户方本身实现的驱动程序,静态代码块中执行注册服务,将驱动注册到驱动管理程序中。ide
public class MysqlDriver implements MyDriver {
static {
MyDriverManager.registerDriver(“mysql”, new MysqlDriver());
}
public MyConnection getConnection(String url) {
System.out.println(“connect to mysql: url = “ + url);
return new MysqlConnection();
}
}
复制代码
实际执行时,要先使用Class.forName加载一下驱动程序,不然static代码块不会执行,没法将驱动加载到驱动管理程序中。url
public class Main {
public static void main(String[] args) throws ClassNotFoundException {
Class.forName(“com.github.yaolang.chapter01.spi1.MysqlDriver”);
MyConnection myConnection = MyDriverManager.getConnection(“mysql://localhost:8080”);
System.out.println(myConnection);
}
}
复制代码
如下为输出结果spa
connect to mysql: url = mysql://localhost:8080
com.github.yaolang.chapter01.spi1.MysqlConnection@60e53b93
复制代码