JDBC数据库驱动注册与Connection获取源码分析

源码分析:

这是Mysql 8.x版的java驱动部分源码

package com.mysql.cj.jdbc;

import java.sql.SQLException;

public class Driver extends NonRegisteringDriver implements java.sql.Driver {
    //
    // Register ourselves with the DriverManager
    //
    static {
        try {
            java.sql.DriverManager.registerDriver(new Driver());
        } catch (SQLException E) {
            throw new RuntimeException("Can't register driver!");
        }
    }

    /**
     * Construct a new driver and register it with DriverManager
     * 
     * @throws SQLException
     *             if a database error occurs.
     */
    public Driver() throws SQLException {
        // Required for Class.forName().newInstance()
    }
}

通过在Driver里的static静态代码块调用java.sql.DriverManager.registerDriver()方法来注册数据库驱动.



public class DriverManager {

    // List of registered JDBC drivers
    private final static CopyOnWriteArrayList<DriverInfo> registeredDrivers = new CopyOnWriteArrayList<>();
    
    .... //省略代码
}

调用registerDriver后,驱动将会被添加到DriverManager的一个线程安全的List中(registeredDrivers)


而当我们通过DriverManager.getConnection()来获得数据库连接时,会从这个list中去除第一个符合要求的driver,在调用driver.connect()获得一个Connection

//  Worker method called by the public getConnection() methods.
    private static Connection getConnection(
        String url, java.util.Properties info, Class<?> caller) throws SQLException {
        /*
         * When callerCl is null, we should check the application's
         * (which is invoking this class indirectly)
         * classloader, so that the JDBC driver class outside rt.jar
         * can be loaded from here.
         */
        ClassLoader callerCL = caller != null ? caller.getClassLoader() : null;
        if (callerCL == null) {
            callerCL = Thread.currentThread().getContextClassLoader();
        }

        if (url == null) {
            throw new SQLException("The url cannot be null", "08001");
        }

        println("DriverManager.getConnection(\"" + url + "\")");

        ensureDriversInitialized();

        // Walk through the loaded registeredDrivers attempting to make a connection.
        // Remember the first exception that gets raised so we can reraise it.
        SQLException reason = null;

        //这里遍历已注册驱动
        for (DriverInfo aDriver : registeredDrivers) {
            // If the caller does not have permission to load the driver then
            // skip it.
            if (isDriverAllowed(aDriver.driver, callerCL)) {
                try {
                    println("    trying " + aDriver.driver.getClass().getName());
                    //这里获得Connection
                    Connection con = aDriver.driver.connect(url, info);
                    if (con != null) {
                        // Success!
                        println("getConnection returning " + aDriver.driver.getClass().getName());
                        return (con);
                    }
                } catch (SQLException ex) {
                    if (reason == null) {
                        reason = ex;
                    }
                }

            } else {
                println("    skipping: " + aDriver.getClass().getName());
            }

        }

        // if we got here nobody could connect.
        if (reason != null)    {
            println("getConnection failed: " + reason);
            throw reason;
        }

        println("getConnection: no suitable driver found for "+ url);
        throw new SQLException("No suitable driver found for "+ url, "08001");
    }

总结:

按Effective Java里的说法,这是服务提供者框架模式,服务接口是java.sql.Driver,提供者注册API是java.sql.DriverManager.registerDriver(),服务访问API是DriverManager.getConnection().这样做的好处是解耦,服务接收者与服务提供者完全解耦,服务接受者不许要指导服务提供者的具体内容即可调用其服务.


欢迎访问我的 个人网站(主要), Github, CSDN(主要), 博客园, 简书, 掘金, 知乎, 微信公众号:HelloVant(主要)

本文采用 知识共享 署名-非商业性使用-禁止演绎(CC by-nc-nd) 4.0 国际 许可协议 授权

发布了39 篇原创文章 · 获赞 48 · 访问量 2万+
展开阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 大白 设计师: CSDN官方博客

分享到微信朋友圈

×

扫一扫,手机浏览