解读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
@CallerSensitivepublic 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 CopyOnWriteArrayListregisteredDrivers = 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;
博客
开源中国博客地址
个人博客地址
欢迎关注我的个人微信订阅号:(据说这个头像程序猿专用)