mysql驱动如何编写_解读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来演示,所以需要导入相关依赖

mysql

mysql-connector-java

5.1.44

以上是最简单的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 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;

博客

开源中国博客地址

个人博客地址

欢迎关注我的个人微信订阅号:(据说这个头像程序猿专用)

a1dd865fb410fb2a4643666a22279cd5.png


版权声明:本文为weixin_35758982原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。