本篇文章将从深入理解java SPI机制来介绍组件化框架设计:
一、SPI机制定义
SPI机制(Service Provider Interface)其实源自服务提供者框架(Service Provider Framework,参考【EffectiveJava】page6),是一种将服务接口与服务实现分离以达到解耦、大大提升了程序可扩展性的机制。引入服务提供者就是引入了spi接口的实现者,通过本地的注册发现获取到具体的实现类,轻松可插拔。
二、典型实例:jdbc的设计
通常各大厂商(如Mysql、Oracle)会根据一个统一的规范(java.sql.Driver)开发各自的驱动实现逻辑。客户端使用jdbc时不需要去改变代码,直接引入不同的spi接口服务即可。
Mysql的则是com.mysql.jdbc.Drive,Oracle则是oracle.jdbc.driver.OracleDriver。
伪代码如下:
//注:从jdbc4.0之后无需这个操作,spi机制会自动找到相关的驱动实现
//Class.forName(driver);
//1.getConnection()方法,连接MySQL数据库。有可能注册了多个Driver,这里通过遍历成功连接后返回。
con = DriverManager.getConnection(mysqlUrl,user,password);
//2.创建statement类对象,用来执行SQL语句!!
Statement statement = con.createStatement();
//3.ResultSet类,用来存放获取的结果集!!
ResultSet rs = statement.executeQuery(sql);
jdbc连接源码分析
java.sql.DriverManager静态块初始执行,其中使用spi机制加载jdbc具体实现
//java.sql.DriverManager.java
//当调用DriverManager.getConnection(..)时,static会在getConnection(..)执行之前被触发执行
/**
* Load the initial JDBC drivers by checking the System property
* jdbc.properties and then use the {@code ServiceLoader} mechanism
*/
static {
loadInitialDrivers();
println("JDBC DriverManager initialized");
}
2.loadInitialDrivers()中完成了引入的数据库驱动的查找以及载入,本示例只引入了oracle厂商的mysql,我们具体看看。
//java.util.serviceLoader.java
private static void loadInitialDrivers() {
String drivers;
try {
drivers = AccessController.doPrivileged(new PrivilegedAction() {
public String run() {
//使用系统变量方式加载
return System.getProperty("jdbc.drivers");
}
});
} catch (Exception ex) {
drivers = null;
}
//如果spi 存在将使用spi方式完成