什么是SPI机制
SPI全称Service Provider Interface,是Java提供的一套用来被第三方实现或者扩展的接口。我们知道JDK代码提供了大量的方便的工具类给我们使用,JDK会对经常使用接口进行抽象统一。如链接数据库我们可以使用java.sql.DriverManager,但各种数据库的实现各自不同,所以为了给用户统一使用,屏蔽底层各自难懂的细节,我们这种SPI机制产生了。
mysql加载驱动
回想我们经常使用mysql的过程
0.配置文件:
url: jdbc:mysql://localhost:3306/xxxxx?autoReconnect=true&useSSL=false&characterEncoding=utf-8&serverTimezone=Asia/Shanghai
username: xxx
password: xxxxxx
1.注册驱动(现在已经不需要这一步加载了,写了也兼容不报错)
Class.forName("com.mysql.jdbc.Driver");
2.创建连接:
conn = (Connection) DriverManager.getConnection(url,username,password);
3.执行sql
stat = conn.createStatement();
String sql = "SELECT * FROM tb_person";
ResultSet rs = stat.executeQuery(sql);
让我们看看java.sql.DriverManager做了什么事情
//类初始化代码加载驱动
static {
loadInitialDrivers();
println("JDBC DriverManager initialized");
}
private static void loadInitialDrivers() {
String drivers;
try {
//加载系统属性jdbc.drivers指定的drivers
drivers = AccessController.doPrivileged(new PrivilegedAction<String>() {
public String run() {
return System.getProperty("jdbc.drivers");
}
});
} catch (Exception ex) {
drivers = null;
}
//如果driver驱动是Service Provider形式的,直接加载,并且替换上面系统属性指定方式
AccessController.doPrivileged(new PrivilegedAction<Void>() {
public Void run() {
//使用ServiceLoader加载Driver
ServiceLoader<Driver> loadedDrivers = ServiceLoader.load(Driver.class);
Iterator<Driver> driversIterator = loadedDrivers.iterator();
//遍历driver,driver有可能不存在或者配置错误,直接catch异常并忽略
try{
while(driversIterator.hasNext()) {
driversIterator.next();
}
} catch(Throwable t) {
// Do nothing
}
return null;
}
});
println("DriverManager.initialize: jdbc.drivers = " + drivers);
if (drivers == null || drivers.equals("")) {
return;
}
String[] driversList = drivers.split(":");
println("number of Drivers:" + driversList.length);
for (String aDriver : driversList) {
try {
println("DriverManager.Initialize: loading " + aDriver);
//这里注意使用了系统类加载器加载驱动
Class.forName(aDriver, true,
ClassLoader