當前位置:
首頁 > 知識 > 解讀MySQL驅動載入邏輯

解讀MySQL驅動載入邏輯

我們很早之前就知道最基礎的JDBC編寫,先執行Class.forName方法,載入MySQL驅動。但是為什麼載入過驅動後,後續的介面層的調用就會自動切換到MySQL的相關代碼去執行呢?(作者:高元)

常見jdbc編寫

Connection connection = null;
PreparedStatement ps = null;
ResultSet rs = null;
try {
Class.forName("com.mysql.jdbc.Driver");
connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/gdjt_db","root","root");
ps = connection.prepareStatement("select * from sys_user where id = ? ");
ps.setString(1, "1");
rs = ps.executeQuery();
while (rs.next()){
System.out.println(rs.getString("name"));
}
}catch (Exception e){
e.printStackTrace();
}finally {
try {
if(rs != null)rs.close();
}catch (Exception e){}
try {
if(ps != null)ps.close();
}catch (Exception e){}
try {
if(connection != null)connection.close();
}catch (Exception e){}
}

當然,我們這裡使用MySQL來演示,所以需要導入相關依賴

<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.44</version>
</dependency>

以上是最簡單的JDBC實現,下面我們主要查看Class.forName("com.mysql.jdbc.Driver");具體的執行邏輯。

查看第一步具體做了什麼?

Class.forName("com.mysql.jdbc.Driver");

1、我們先看Class.forName

@CallerSensitive
public static Class<?> forName(String className) throws ClassNotFoundException {
/** 獲取調用者Class */
Class<?> caller = Reflection.getCallerClass();
/**
* 1、獲取調用者的類載入器
* 2、執行類載入
* 3、執行初始化方法(initialize = true)
*/
return forName0(className, true, ClassLoader.getClassLoader(caller), caller);
}

具體內容見代碼中的註解,可以發現,Class.forName主要就是類載入,載入了類com.mysql.jdbc.Driver

2、接著看mysql的Driver源碼實現

/**
* java.sql.Driver 是jdk封裝的驅動介面
*/
public class Driver extends NonRegisteringDriver implements java.sql.Driver {
public Driver() throws SQLException {
}

/** 上一步驟類載入器載入類時,執行了初始化方法,就是執行這裡的static中的代碼 */
static {
try {
/** 將當前mysql的Driver註冊到DriverManager中 */
DriverManager.registerDriver(new Driver());
} catch (SQLException var1) {
throw new RuntimeException("Can"t register driver!");
}
}
}

具體註冊代碼如下:

public static synchronized void registerDriver(java.sql.Driver driver, DriverAction da) throws SQLException {
if(driver != null) {
// 將mysql的driver封裝成DriverInfo對象,並傳入registeredDrivers鏈表中。
registeredDrivers.addIfAbsent(new DriverInfo(driver, da));
} else {
throw new NullPointerException();
}
}

其中 registeredDrivers 是全局的靜態變數

private final static CopyOnWriteArrayList<DriverInfo> registeredDrivers = new CopyOnWriteArrayList<>();

這樣,無論在哪裡,都可以通過registeredDrivers來獲取當前的驅動。

3、繼續看Connection如何獲取到對應的連接的

Connection conn = DriverManager.getConnection(url,username,password);

我們進入getConnection查看,代碼稍微長點,不過沒關係,我們只要看如下一行代碼即可

private static Connection getConnection(String url, java.util.Properties info, Class<?> caller) throws SQLException {
...
// 看到了熟悉的身影 registeredDrivers
for(DriverInfo aDriver : registeredDrivers) {
...
// 從registeredDrivers獲取之前存入的mysql對應的Driver
Connection con = aDriver.driver.connect(url, info);
...
}
...
}

接著執行 driver.connect( ) 方法,之前我們看過 Driver 的源碼

Driver extends NonRegisteringDriver implements java.sql.Driver

所以 driver.connect 的方法,不是在 Driver 中就是在 NonRegisteringDriver 中。 結果我們在 NonRegisteringDriver 中如願以償的找到了connect方法(118行左右)

public Connection connect(String url, Properties info) throws SQLException {
...
// 重要代碼在這裡,獲取具體的連接實例
com.mysql.jdbc.Connection newConn = ConnectionImpl.getInstance(this.host(props), this.port(props), props, this.database(props), url);
return newConn;
...
}

接下來的步驟就不一一演示了。

總結

  • 通過類載入器載入Driver並初始化,將Driver添加到DriverManager的registeredDrivers中;
  • 通過registeredDrivers獲取到Driver;
  • 調用Driver的connect方法,獲取Mysql中的MySQLConnection;

解讀MySQL驅動載入邏輯

喜歡這篇文章嗎?立刻分享出去讓更多人知道吧!

本站內容充實豐富,博大精深,小編精選每日熱門資訊,隨時更新,點擊「搶先收到最新資訊」瀏覽吧!


請您繼續閱讀更多來自 程序員小新人學習 的精彩文章:

為什麼我們做分散式的使用都是用Redis?
區塊鏈教程之基礎開發通過介面查詢幣種提幣情況bch

TAG:程序員小新人學習 |