SPI在JDBC中的運用
前言
之前學習了JDK SPI的機制,本文專門討論2個內容:
1.為什麼在使用SPI後,不需要Class.forName()了?
2.SPI在JDBC中的運用。
JDBC模板程式碼
private static final String URL = "jdbc:mysql://localhost:3306/demo?useSSL=true&useUnicode=true&characterEncoding=UTF-8"; private static final String DRIVER = "com.mysql.jdbc.Driver"; //載入驅動資訊,使用SPI之後,不需要下面這行程式碼了。 static { try { Class.forName(DRIVER); } catch (ClassNotFoundException e) { e.printStackTrace(); } } public static void main(String[] args) throws Exception { Connection conn = DriverManager.getConnection(url, user, password); String sql = "insert into user (name, pwd) values(?,?)"; Statement st = conn.createStatement(); st.executeQuery(sql); }
為什麼在使用SPI後,不需要Class.forName()了?
首先我們需要了解:Class.forName("com.mysql.jdbc.Driver")的作用是:
根據JVM類載入的原理,該程式碼會將這個位元組碼檔案載入到虛擬機器內部,
而由於類載入共有7個階段,並且Class.forName()方法中使用了JDK反射包中Class<?> caller = Reflection.getCallerClass();
所以,Class.forName()方法不僅僅會載入Driver類,還會執行它的類初始化的過程(即靜態程式碼塊,靜態變數賦值等操作)
其次我們看看為什麼不需要Class.forName()了?
我們來分析一下main方法中的第一句原始碼:Connection conn = DriverManager.getConnection(url, user, password);
首先呼叫該方法前,JVM會載入DriverManager類,然後執行連線,初始化。
DriverManager.Class原始碼 /** * Load the initial JDBC drivers by checking the System property * jdbc.properties and then use the {@code ServiceLoader} mechanism * 這裡清楚的說明了,該程式碼塊會使用SPI機制進行服務發現。 */ static { loadInitialDrivers(); println("JDBC DriverManager initialized"); }
然後跟蹤程式碼loadInitialDrivers();
會發現:
ServiceLoader<Driver> loadedDrivers = ServiceLoader.load(Driver.class);
Iterator<Driver> driversIterator = loadedDrivers.iterator();
/*
* 省略註釋
*/
try{
while(driversIterator.hasNext()) {
driversIterator.next();
}
} catch(Throwable t) {
// Do nothing
}
我的上一篇部落格JDK中的SPI機制中的例1和這裡是一樣的,因為我本來也是參考它來學習的。
根據上一篇部落格裡面的類載入分析,我們知道了這裡DriverManager.Class的靜態初始化,和顯示的執行Class.forName()是一致的。
因為他們使用的類載入器分別是:
1.DriverManager.Class靜態初始化內的SPI機制所使用的是:執行緒上下文類載入器,預設為系統類載入器AppClassLoader。
2.Class.forName()為main方法所在的類的類載入器:系統類載入器AppClassLoader。
所以這裡預設是同一個類載入器來載入我們classpath下面的com.mysql.jdbc.Driver
。
綜上:
1.在使用SPI後,不需要顯示呼叫Class.forName()了。
2.SPI在JDBC中的運用就是如此,它使用了SPI來對實現方做了約束,並把實現獨立於實現方中,JDK這樣來提供了一種服務提供發現機制.