20170415_DriverManager获取Connection

问题的引出

为什么我们通过DriverManager.getConnection(url, username, password)获取到的是Connection是一个接口,却能调用方法?不是说接口只是一个抽象的东西?不能做具体的事情么?
那我们通过DriverManager获取到的Connection接口为什么可以做获取Statement对象之类的事情?

首先我们看我们获取到的对象是怎么样获取的:

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

这种获取方法是不是很眼熟?我们看一下从小学到大的一个创建对象的写法:

    Person person=new Student();

这样来看是不是很熟悉?是不是我们的父类引用指向子类对象?

所以我们实际上通过DriverManager.getConnection(url, username, password)获取到的是实现了Connection接口的实体对象

我们接着看DriverManager是怎么获取到Connection实体对象的,先通过DriverManager.getConnection(url, username, password)跳到源码位置

DvierManamger的方法

        public static Connection getConnection(String url,
            String user, String password) throws SQLException {
            java.util.Properties info = new java.util.Properties();//创建了一个Properties对象来存放信息
    
            if (user != null) {
                info.put("user", user);//如果user不为空,将user信息存入info对象
            }
            if (password != null) {
                info.put("password", password);//如果password不为空,将password信息存入info对象
            }
    
            //再通过另一个重载的getConnection方法获取连接
            return (getConnection(url, info, Reflection.getCallerClass()));
        }

我们在第一次跳转进来的方法中是没法直接获取实现了Connection接口的实体类的,这里还要通过DriverManger的重载方法继续做做事情,接着我们进到getConnection(url, info, Reflection.getCallerClass())方法

        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;
                synchronized(DriverManager.class) {
                    // synchronize loading of the correct classloader.
                    if (callerCL == null) {
                        callerCL = Thread.currentThread().getContextClassLoader();
                    }
                }
        
                if(url == null) {
                    throw new SQLException("The url cannot be null", "08001");
                }
        
                println("DriverManager.getConnection(\"" + url + "\")");
        
                // 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 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");
            }

这一整个方法我们不用全部关心,找到切入点,我们现在知道自己在找Connection,和Connection息息相关的是Driver,那我们现在就针对这两个对象来查找,可以看到这个方法里的这段关键代码

     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 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());
                }
    
            }

这个增强for循环中有一个registeredDrivers对象,我们通过查看可以知道他是一个ArrayList,存在这个List的对象是DriverInfo,现在先看一下DriverInfo

    final Driver driver;
    DriverAction da;
    DriverInfo(Driver driver, DriverAction action) {
        this.driver = driver;
        da = action;
    }

可以看到他接收了一个成员变量driver,那我们初步可以判断,DriverManager是通过registeredDrivers这个集合来获取已经注册好的驱动,那registeredDrivers这个集合是在什么地方添加对象的呢?

    public static synchronized void registerDriver(java.sql.Driver driver,
            DriverAction da)
        throws SQLException {

        /* Register the driver if it has not already been added to our list */
        if(driver != null) {
            registeredDrivers.addIfAbsent(new DriverInfo(driver, da));
        } else {
            // This is for compatibility with the original DriverManager
            throw new NullPointerException();
        }

        println("registerDriver: " + driver);

    }

根据关键字"registeredDrivers"查找,我们发现了registerDriver这个方法,如果driver对象不为空就尝试进行添加,如果没有添加过,我们就会将该driver对象加入registerDriver集合中,而注册驱动是我们第一步做的事情,所以在我们注册驱动的时候,已经将com.mysql.jdbc.Driver加到了该集合中

再回到增强for循环看他做了什么事

         Connection con = aDriver.driver.connect(url, info);
            if (con != null) {
                // Success!
                println("getConnection returning " + aDriver.driver.getClass().getName());
                return (con);
            }

DriverManger通过每次遍历到的aDriver获取里面的driver对象,再调用它的connect方法,将url(数据库地址),info(访问用户名,访问密码)拿来使用,获取实现了Connection接口的实现类,到此,我们初步可以看到DriverManager是如何获取Connection实现类的了

去到我们注册的com.mysql.jdbc.Driver类中找connect方法,发现没找到,那子类没有的方法一般父类会有,我们继续往父类com.mysql.jdbc.NonRegisteringDriver那查找connect(url,info)方法

我们在父类com.mysql.jdbc.NonRegisteringDriver中可以找到下面方法:

    public java.sql.Connection connect(String url, Properties info) throws SQLException

在这个方法里我们就能看到它在返回ConnectionImpl对象了

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,928评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,192评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,468评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,186评论 1 286
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,295评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,374评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,403评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,186评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,610评论 1 306
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,906评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,075评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,755评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,393评论 3 320
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,079评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,313评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,934评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,963评论 2 351

推荐阅读更多精彩内容