JDBC加載流程分析

問題拋出
jdbc只是接口端考,數據庫驅動是其實現图仓,是如何找到驅動并進行加載使用罐盔?類路徑有多個數據庫驅動實現的時候,該選擇哪個救崔?

jdbc模板示例

下面是jdbc接入的范例惶看,首先將數據庫驅動添加到工程中,其中加載驅動程序的代碼是可選的Class.forName("com.mysql.jdbc.Driver");帚豪,可以不寫碳竟。那么問題來了,程序是如何找到驅動程序并完成加載呢狸臣?

public class DbUtil {
    public static final String URL = "jdbc:mysql://localhost:3306/imooc";
    public static final String USER = "liulx";
    public static final String PASSWORD = "123456";

    public static void main(String[] args) throws Exception {
        //1.加載驅動程序
        Class.forName("com.mysql.jdbc.Driver");
        //2. 獲得數據庫連接
        Connection conn = DriverManager.getConnection(URL, USER, PASSWORD);
        //3.操作數據庫,實現增刪改查
        Statement stmt = conn.createStatement();
        ResultSet rs = stmt.executeQuery("SELECT user_name, age FROM imooc_goddess");
        //4. 如果有數據昌执,rs.next()返回true
        while(rs.next()){
            System.out.println(rs.getString("user_name")+" 年齡:"+rs.getInt("age"));
        }
    }
}

驅動類加載的時機

首先烛亦,通過DriverManager找到數據庫驅動诈泼,并進行加載。

 Connection conn = DriverManager.getConnection(URL, USER, PASSWORD);

DriverManager用來管理類路徑中的數據庫驅動煤禽。如何找到數據庫驅動類铐达,關鍵點在于,ServiceLoader SPI檬果,加載Driver.class瓮孙。這個loadInitialDrivers是DriverManager加載時觸發(fā)的。

具體代碼如下

public class DriverManager{
    private DriverManager(){}   
    static {
        loadInitialDrivers();//加載驅動
        println("JDBC DriverManager initialized");
    }

    private static void loadInitialDrivers() {
        String drivers;
        try {
            drivers = AccessController.doPrivileged(new PrivilegedAction<String>() {
                public String run() {
                    return System.getProperty("jdbc.drivers");
                }
            });
        } catch (Exception ex) {
            drivers = null;
        }
        AccessController.doPrivileged(new PrivilegedAction<Void>() {
            public Void run() {
                // 通過ServiceLoader加載Driver類
                ServiceLoader<Driver> loadedDrivers = ServiceLoader.load(Driver.class);
                Iterator<Driver> driversIterator = loadedDrivers.iterator();
                try{
                    while(driversIterator.hasNext()) {
                        driversIterator.next();
                    }
                } catch(Throwable t) {
                // Do nothing
                }
                return null;
            }
        });

        println("DriverManager.initialize: jdbc.drivers = " + drivers);

        if (drivers == null || drivers.equals("")) {
            return;
        }
        String[] driversList = drivers.split(":");
        println("number of Drivers:" + driversList.length);
        for (String aDriver : driversList) {
            try {
                println("DriverManager.Initialize: loading " + aDriver);
                Class.forName(aDriver, true,
                        ClassLoader.getSystemClassLoader());
            } catch (Exception ex) {
                println("DriverManager.Initialize: load failed: " + ex);
            }
        }
    }
}

ServiceLoader

一般使用接口的實現類都是靜態(tài)new一個實現類賦值給接口引用选脊,如下:

HelloService service = new HelloImpl();

如果需要動態(tài)的獲取一個接口的實現類呢杭抠?全局掃描全部的Class,然后判斷是否實現了某個接口恳啥?代價太大偏灿,一般不會這么做。一種合適的方式就是使用配置文件钝的,把實現類名配置在某個地方翁垂,然后讀取這個配置文件,獲取實現類名硝桩。JDK提供的ServiceLoader就是這種方式沿猜。
具體用法,就是在實現類的jar包的META-INF下新建一個文件夾services碗脊,并在services下新建一個文件啼肩,以接口的全限定名為文件名,內容為實現類的全限定名望薄。

怎么找到驅動類疟游?

ServiceLoader<Driver> loadedDrivers = ServiceLoader.load(Driver.class);

DriverManager加載的時候,會load Driver.class痕支,Driver.class的全限定名是java.sql.Driver颁虐。

mysql驅動serviceLoader示例

也就是通過ServiceLoader機制,完成了驅動類的加載

如何選擇驅動類卧须?

當類路徑有多個驅動類時另绩,通過配置來匹配驅動,完成驅動的初始化花嘶。

    public static final String URL = "jdbc:mysql://localhost:3306/imooc";
    Connection conn = DriverManager.getConnection(URL, USER, PASSWORD);

url指定了采用的協議是jdbc:mysql笋籽,

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市椭员,隨后出現的幾起案子车海,更是在濱河造成了極大的恐慌,老刑警劉巖隘击,帶你破解...
    沈念sama閱讀 212,542評論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件侍芝,死亡現場離奇詭異研铆,居然都是意外死亡,警方通過查閱死者的電腦和手機州叠,發(fā)現死者居然都...
    沈念sama閱讀 90,596評論 3 385
  • 文/潘曉璐 我一進店門棵红,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人咧栗,你說我怎么就攤上這事逆甜。” “怎么了致板?”我有些...
    開封第一講書人閱讀 158,021評論 0 348
  • 文/不壞的土叔 我叫張陵交煞,是天一觀的道長。 經常有香客問我可岂,道長错敢,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,682評論 1 284
  • 正文 為了忘掉前任缕粹,我火速辦了婚禮稚茅,結果婚禮上,老公的妹妹穿的比我還像新娘平斩。我一直安慰自己亚享,他們只是感情好,可當我...
    茶點故事閱讀 65,792評論 6 386
  • 文/花漫 我一把揭開白布绘面。 她就那樣靜靜地躺著欺税,像睡著了一般。 火紅的嫁衣襯著肌膚如雪揭璃。 梳的紋絲不亂的頭發(fā)上晚凿,一...
    開封第一講書人閱讀 49,985評論 1 291
  • 那天,我揣著相機與錄音瘦馍,去河邊找鬼歼秽。 笑死,一個胖子當著我的面吹牛情组,可吹牛的內容都是我干的燥筷。 我是一名探鬼主播,決...
    沈念sama閱讀 39,107評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼院崇,長吁一口氣:“原來是場噩夢啊……” “哼肆氓!你這毒婦竟也來了?” 一聲冷哼從身側響起底瓣,我...
    開封第一講書人閱讀 37,845評論 0 268
  • 序言:老撾萬榮一對情侶失蹤谢揪,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發(fā)現了一具尸體键耕,經...
    沈念sama閱讀 44,299評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡寺滚,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 36,612評論 2 327
  • 正文 我和宋清朗相戀三年柑营,在試婚紗的時候發(fā)現自己被綠了屈雄。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,747評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡官套,死狀恐怖酒奶,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情奶赔,我是刑警寧澤惋嚎,帶...
    沈念sama閱讀 34,441評論 4 333
  • 正文 年R本政府宣布,位于F島的核電站站刑,受9級特大地震影響另伍,放射性物質發(fā)生泄漏。R本人自食惡果不足惜绞旅,卻給世界環(huán)境...
    茶點故事閱讀 40,072評論 3 317
  • 文/蒙蒙 一摆尝、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧因悲,春花似錦堕汞、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,828評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至卫旱,卻和暖如春人灼,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背顾翼。 一陣腳步聲響...
    開封第一講書人閱讀 32,069評論 1 267
  • 我被黑心中介騙來泰國打工投放, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人暴构。 一個月前我還...
    沈念sama閱讀 46,545評論 2 362
  • 正文 我出身青樓跪呈,卻偏偏與公主長得像,于是被迫代替她去往敵國和親取逾。 傳聞我的和親對象是個殘疾皇子耗绿,可洞房花燭夜當晚...
    茶點故事閱讀 43,658評論 2 350

推薦閱讀更多精彩內容