亚洲国产成人精品久久_欧美日韩国产综合一区二区_亚洲精品理论电影_色综合久久中文字幕

一個程序使用相同數(shù)據(jù)庫的兩個不同版本的jar包

放大字體  縮小字體 發(fā)布日期:2019-11-14  來源:來自互聯(lián)網(wǎng)  作者:來自互聯(lián)網(wǎng)  瀏覽次數(shù):871
導(dǎo)讀

} 這里的classloader的調(diào)用getConnection的對象的classloader,driver則是驅(qū)動注冊到DriverManager的對象,這里通過classloader再次加載d…

問題場景

現(xiàn)在很多工程為了功能擴(kuò)展,都給出了插件化的方式。只需要用戶配置好配置文件,提供好需要的jar包,就能完成響應(yīng)功能。本文說一下,數(shù)據(jù)轉(zhuǎn)存數(shù)的功能實現(xiàn)。現(xiàn)在項目一般都離不開數(shù)據(jù)庫,自己本身的項目就會帶這驅(qū)動包,但是也會有這樣的一種需求,就是數(shù)據(jù)額外存儲的定制化,當(dāng)產(chǎn)生的數(shù)據(jù)在自己項目的流程中不滿足現(xiàn)在使用。例如做報表,項目本身產(chǎn)生數(shù)據(jù),但是需要把里面的一部分?jǐn)?shù)據(jù)拿出來和其他文本數(shù)據(jù)結(jié)合,產(chǎn)生新的數(shù)據(jù)。或者現(xiàn)有的數(shù)據(jù)進(jìn)行時間的整合,直接變成周數(shù)據(jù),月數(shù)據(jù),年數(shù)據(jù)。這些都是需要根據(jù)不同用戶自己設(shè)定的。這些數(shù)據(jù)往往是需要另外的數(shù)據(jù)庫的,這就帶來了一個問題,項目本身有一個jar包,例如Mysql4.5的,客戶想組織信息存入mysql5.5,jar包的類是相同的,這樣就帶來了驅(qū)動加載的問題,因為類的相同的,而且驅(qū)動不是完全不兼容,而是在使用上會出問題。典型的就是ojdbc14,用這個版本的驅(qū)動建立數(shù)據(jù)庫使用語句池緩存會有問題,ojdbc5,6就沒事。(畢竟語句池緩存能帶來性能上優(yōu)化,不能說為了兼容驅(qū)動放棄性能,而且其他潛在的問題還沒有暴露)。

問題分析

本質(zhì)上就是一個獲取正確連接的問題,我們正常使用驅(qū)動第一件事就是class.forname(xxxxx),mysql(注冊肯定是需要注冊的,但是不一定發(fā)生在class.forname上)的話就是把驅(qū)動類注冊到了DriverManager上,然后我們通過DriverManager來獲取connection對象。getConnection的過程可以分為以下步驟。

1,驗證對象

private static boolean isDriverAllowed(Driver driver, ClassLoader classLoader) {

boolean result = false;

if(driver != null) {

Class aClass = null;

try {

aClass = Class.forName(driver.getClass().getName(), true, classLoader);

} catch (Exception ex) {

result = false;

}

result = ( aClass == driver.getClass() ) ? true : false;

}

return result;

}

這里的classloader的調(diào)用getConnection的對象的classloader,driver則是驅(qū)動注冊到DriverManager的對象,這里通過classloader再次加載driver類,這里如果加載到的class和driver是一樣的,當(dāng)前的classloader要不是加載驅(qū)動的classloader,要不就是其子classloader,以此保持不會出現(xiàn)類A非類A的問題(classloader的經(jīng)典問題)。

2,獲取連接

for(DriverInfo aDriver : registeredDrivers) {

if(isDriverAllowed(aDriver.driver, callerCL)) {

try {

println( trying + aDriver.driver.getClass().getName());

Connection con = aDriver.driver.connect(url, info);

if (con != null) {

println(getConnection returning + aDriver.driver.getClass().getName());

return (con);

}

} catch (SQLException ex) {

if (reason == null) {

reason = ex;

}

}

} else {

println( skipping: + aDriver.getClass().getName());

}

}

這里就是獲取連接的過程,registeredDrivers就是已經(jīng)注冊的驅(qū)動,它是一個集合,下面是聲明。

private final static CopyonWriteArrayList registeredDrivers = new CopyonWriteArrayList();

這樣可以看到,只要通過檢驗就獲取連接,獲取成功就返回,這就是我們獲取的connection對象。這里的一個明顯問題就是集合是一個線程安全的鏈表,誰先被加載誰先去獲取connection對象。如果按照以往的方式,這里有兩個難題,一個是classloader的驗證,一個是遍歷的順序。看起來只要讓classloader驗證正確,那么就可以保證遍歷的的時候正確的loader加載正確的驅(qū)動了。很明顯jdk不讓你這么玩,因為這個方法是private的,這就必須保證你調(diào)用的classloader和注冊的classloader必須是同一個,注冊的還簡單,但是調(diào)用的classloader也這樣,那就必須把代碼實現(xiàn)打包出來,這樣很不利于我們管理。

以上我們看通了java的連接流程,那么我們嘗試做精簡,提取關(guān)鍵代碼。

Connection con = aDriver.driver.connect(url, info);

其實獲取連接就這樣一句話,剩下的內(nèi)容都是為了保證這句話正確執(zhí)行的校驗,現(xiàn)在我們自己來保證這個校驗,這樣就把關(guān)鍵邏輯簡化成獲取Driver對象,獲取Connection對象,2個過程。無論怎么思考,都繞不過classloader,所以自定義classloader是肯定繞不過去了。我們借助classloader來保證加載的驅(qū)動類是正確的,這點就比較容易的實現(xiàn)了。

實現(xiàn)

首先需要一個違背雙親委托的classloader,不知道怎么寫的可以查看我上一篇文章。地址:https://my.oschina/xpbob/blog/761436

這種classloader很好的保證了我們加載的安全性,因為地址是我們指定的,用戶扔進(jìn)去多個相同版本那和在was的lib目錄下扔入效果一樣,都不保證正常運(yùn)行。簡單寫一個使用方式。

public static void main(String[] args) throws Exception {

// TODO Auto-generated method stub

String url =jdbc:mysql://127.0.0.1/test;

String user=root;

String password =;

String driverClass=com.mysql.jdbc.Driver;

File file = new File(c:/mysql-connector-java-5.1.8.jar);

MyClassloader loader = new MyClassloader(new URL[]{file.toURL()});

Driver driver = (Driver) loader.loadClass(driverClass).newInstance();

java.util.Properties info = new java.util.Properties();

if (user != null) {

info.put(user, user);

}

if (password != null) {

info.put(password, password);

}

Connection connect = driver.connect(url, info);

if(connect!=null){

System.out.println(success);

}else{

System.out.println(error);

}

}

上面的url,username等等信息都是連接數(shù)據(jù)庫必要的信息,可以寫死也可以指定,然后那個file路徑是我指定的地址,在c盤,根據(jù)項目來設(shè)定。這里直接生成driver對象,此處就是com.mysql.jdbc.Driver,這里就體現(xiàn)到面向接口編程的好處了,Driver類是jdk的,只要保證路徑就都能加載到,不會出現(xiàn)沖突。運(yùn)行代碼,顯示success就表示你成功獲取connection對象,剩下就是操作數(shù)據(jù)庫語句的邏輯了。

 
 
免責(zé)聲明
本文為會員免費(fèi)發(fā)布,僅代表發(fā)布者個人觀點,本站未對其內(nèi)容進(jìn)行核實,請讀者僅做參考,如若文中涉及有違公德、觸犯法律的內(nèi)容,一經(jīng)發(fā)現(xiàn),立即刪除,作者需自行承擔(dān)相應(yīng)責(zé)任。涉及到版權(quán)或其他問題,請及時聯(lián)系我們刪除處理。
 
 
主站蜘蛛池模板: 日韩中文字幕av在线| 日本久久久网站| 日韩免费黄色av| 欧美精品尤物在线| 国产精品久久久久久久7电影| 日本亚洲欧洲精品| 91精品在线观| 国产欧美日韩一区| 久久国产精品视频| 久久99精品国产99久久| 青青久久av北条麻妃黑人| 色综合久久中文字幕综合网小说| 国产精品久久久久久免费观看| 狠狠色综合色区| 精品国偷自产在线视频| 久久免费国产视频| 久久日韩精品| 欧美激情极品视频| 日韩欧美在线免费观看视频| 91国产精品91| 亚洲自拍中文字幕| 伊人久久99| 中文精品无码中文字幕无码专区| 国产精品久久久91| 国产欧美中文字幕| 国产日韩在线精品av| 久久精品日韩| 国产在线视频不卡| 国产精品视频26uuu| 国产成人一区三区| 97国产精品久久| 97成人在线观看视频| 91精品国产91久久久久久久久| 97久久精品国产| 亚洲一区二区三区av无码| 色乱码一区二区三在线看| 日本精品久久久| 国产精品美腿一区在线看| 色综合色综合网色综合| 精品激情国产视频| 日韩av免费看网站|