版權(quán)說(shuō)明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡(jiǎn)介
第java開(kāi)發(fā)ServiceLoader實(shí)現(xiàn)機(jī)制及SPI應(yīng)用目錄前言如何繞過(guò)雙親委派模式ServiceLoader實(shí)現(xiàn)機(jī)制SPI在各個(gè)框架上的應(yīng)用小結(jié)
前言
做過(guò)javaweb開(kāi)發(fā)的小伙伴大多數(shù)時(shí)候都需要鏈接數(shù)據(jù)庫(kù),這個(gè)時(shí)候就需要配置數(shù)據(jù)庫(kù)引擎DriverClassName參數(shù),這樣我們的java應(yīng)用才能通過(guò)數(shù)據(jù)庫(kù)廠商給的Driver與指定的數(shù)據(jù)庫(kù)建立通信。但是這里就有一個(gè)疑問(wèn):
java.sql.Driver是jdk自帶的接口,它是由BoostrapClassLoader加載的,DriverClassName是外部廠商提供的具體實(shí)現(xiàn),是由AppClassLoader加載的,要建立與數(shù)據(jù)庫(kù)的通信,必然是通過(guò)java.sql.Driver接口方法發(fā)起的,那么在java.sql.Driver是如何拿到具體實(shí)現(xiàn)的呢?它是不是違背了ClassLoader的雙親委派模式呢?
如何繞過(guò)雙親委派模式
為了拿到AppClassLoader中加載的java.sql.Driver實(shí)現(xiàn)類,我們可以查看一下DriverManager是怎么處理的:
publicstaticDrivergetDriver(Stringurl)
throwsSQLException{
println("DriverManager.getDriver(""+url+"")");
ensureDriversInitialized();
......
privatestaticvoidensureDriversInitialized(){
......
AccessController.doPrivileged(newPrivilegedActionVoid(){
publicVoidrun(){
//核心代碼ServiceLoader
ServiceLoaderDriverloadedDrivers=ServiceLoader.load(Driver.class);
IteratorDriverdriversIterator=loadedDrivers.iterator();
try{
while(driversIterator.hasNext()){
driversIterator.next();
}catch(Throwablet){
//Donothing
returnnull;
......
我們最終可以發(fā)現(xiàn),DriverManager通過(guò)ServiceLoader.load(Driver.class)就拿到了我們配置的DriverClassName實(shí)現(xiàn)類。這就實(shí)現(xiàn)在DriverManager中拿到了外部提供的Driver實(shí)現(xiàn),繞過(guò)來(lái)雙親委派模式。
ServiceLoader實(shí)現(xiàn)機(jī)制
我們來(lái)看一下ServiceLoader是如何實(shí)現(xiàn)SPI機(jī)制的,先從ServiceLoader.load()方法入手:
publicstaticSServiceLoaderSload(ClassSservice){
//從當(dāng)前線程中獲取ClassLoader
ClassLoadercl=Thread.currentThread().getContextClassLoader();
//創(chuàng)建一個(gè)ServiceLoader對(duì)象
returnnewServiceLoader(Reflection.getCallerClass(),service,cl);
1.從當(dāng)前線程中獲取ClassLoader;因?yàn)樵趧?chuàng)建AppClassLoader后,將AppClassLoader設(shè)置進(jìn)當(dāng)前線程的上下文中;
2.根據(jù)ClassLoader以及目標(biāo)接口類創(chuàng)建一個(gè)ServiceLoader對(duì)象;
其實(shí)ServiceLoader核心代碼在hasNext()方法中:
@Override
publicbooleanhasNext(){
if(acc==null){
returnhasNextService();
}else{
PrivilegedActionBooleanaction=newPrivilegedAction(){
publicBooleanrun(){returnhasNextService();}
returnAccessController.doPrivileged(action,acc);
最終都會(huì)調(diào)用到hasNextService()方法中:
privatebooleanhasNextService(){
//nextProvider默認(rèn)為null,如果通過(guò)next()取出來(lái)了,nextProvider就會(huì)變成null
while(nextProvider==nullnextError==null){
try{
//找到目標(biāo)實(shí)現(xiàn)類
Classclazz=nextProviderClass();
if(clazz==null)
returnfalse;
if(clazz.getModule().isNamed()){
//ignoreclassifinnamedmodule
continue;
//判斷service接口是否和clazz有父子關(guān)系
if(service.isAssignableFrom(clazz)){
ClassextendsStype=(ClassextendsS)clazz;
//獲取無(wú)參構(gòu)造函數(shù)
ConstructorextendsSctor
=(ConstructorextendsS)getConstructor(clazz);
//包裝成一個(gè)ProviderImpl對(duì)象
ProviderImplSp=newProviderImplS(service,type,ctor,acc);
//并賦值給nextProvider
nextProvider=(ProviderImplT
}else{
fail(service,clazz.getName()+"notasubtype");
}catch(ServiceConfigurationErrore){
nextError=e;
returntrue;
外部提供的實(shí)現(xiàn)類一定要有一個(gè)無(wú)參構(gòu)造函數(shù),否則會(huì)導(dǎo)致ServiceLoader加載失?。?/p>
我們下面再繼續(xù)深入看看ServiceLoader是怎么找到實(shí)現(xiàn)類的:
privateClassnextProviderClass(){
if(configs==null){
try{
//拼接文件名:"META-INF/services/接口名稱"
//比如接口名為:java.sql.Driver,
//那么文件路徑就是:"META-INF/services/java.sql.Driver"
StringfullName=PREFIX+service.getName();
//沒(méi)有指定ClassLoader,就通過(guò)getSystemClassLoader()加載目標(biāo)文件
if(loader==null){
configs=ClassLoader.getSystemResources(fullName);
}elseif(loader==ClassLoaders.platformClassLoader()){
//如果是platformClassLoader,它沒(méi)有classpath,那么看看BootLoader有沒(méi)有classpath
if(BootLoader.hasClassPath()){
configs=BootLoader.findResources(fullName);
}else{
configs=Collections.emptyEnumeration();
}else{
//通過(guò)指定classLoader加載目標(biāo)文件
configs=loader.getResources(fullName);
}catch(IOExceptionx){
fail(service,"Errorlocatingconfigurationfiles",x);
//上面代碼只會(huì)執(zhí)行一次,這樣configs就不會(huì)為null,下次進(jìn)來(lái)直接取下一個(gè)實(shí)現(xiàn)類
//把configs內(nèi)容解析成一個(gè)迭代器
while((pending==null)||!pending.hasNext()){
if(!configs.hasMoreElements()){
returnnull;
pending=parse(configs.nextElement());
//通過(guò)迭代器獲取下一個(gè)實(shí)現(xiàn)類名稱
Stringcn=pending.next();
try{
//通過(guò)類名反射成Class對(duì)象
returnClass.forName(cn,false,loader);
}catch(ClassNotFoundExceptionx){
fail(service,"Provider"+cn+"notfound");
returnnull;
1.實(shí)現(xiàn)類的載入是因?yàn)樵贛ETA-INF/services/文件夾中創(chuàng)建了以目標(biāo)接口名稱命名的文件,并在里面寫(xiě)上了實(shí)現(xiàn)類的全路徑類名。
2.ServiceLoader通過(guò)ClassLoader從classpath中載入目標(biāo)文件里面的內(nèi)容,并解析出實(shí)現(xiàn)類的全路徑類名;
3.最終通過(guò)反射的方式創(chuàng)建出實(shí)現(xiàn)類的Class對(duì)象,這樣就完成了SPI的實(shí)現(xiàn);
SPI在各個(gè)框架上的應(yīng)用
除了在數(shù)據(jù)庫(kù)Driver上使用了SPI,我們還可以發(fā)現(xiàn)SPI在各個(gè)框架上都有大量的應(yīng)用。比如我最近在看的Seata分布式事務(wù)框架,里面就有用到SPI:mon.loader.EnhancedServiceLoader
另一個(gè)就是我們經(jīng)常使用的mysql-connector-java以及阿里的Druid:
小結(jié)
通過(guò)以上源碼分析以及示例演示,我們簡(jiǎn)單做一個(gè)小結(jié):
溫馨提示
- 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 2026外貿(mào)業(yè)務(wù)員考試國(guó)際商法國(guó)際慣例應(yīng)用題集
- 2026年投資理財(cái)知識(shí)學(xué)習(xí)試題
- 2026年經(jīng)濟(jì)學(xué)疑難案例解析與處罰分析
- 軟件開(kāi)發(fā)流程規(guī)范與標(biāo)準(zhǔn)(標(biāo)準(zhǔn)版)
- 汽車銷售與服務(wù)操作手冊(cè)(標(biāo)準(zhǔn)版)
- 未來(lái)五年塑料角閥市場(chǎng)需求變化趨勢(shì)與商業(yè)創(chuàng)新機(jī)遇分析研究報(bào)告
- 遵義市播州區(qū)2025年網(wǎng)格員考試試題及答案
- 鄭州市二七區(qū)2025年網(wǎng)格員考試試題及答案
- 未來(lái)五年外國(guó)快餐行業(yè)市場(chǎng)營(yíng)銷創(chuàng)新戰(zhàn)略制定與實(shí)施分析研究報(bào)告
- 未來(lái)五年寵物美容服務(wù)企業(yè)數(shù)字化轉(zhuǎn)型與智慧升級(jí)戰(zhàn)略分析研究報(bào)告
- 2026年湖南師大附中雙語(yǔ)實(shí)驗(yàn)學(xué)校(南校區(qū))教師招聘?jìng)淇碱}庫(kù)完整參考答案詳解
- 2026年廣州市黃埔區(qū)穗東街招考編外服務(wù)人員易考易錯(cuò)模擬試題(共500題)試卷后附參考答案
- 2026湖南衡陽(yáng)耒陽(yáng)市公安局招聘75名警務(wù)輔助人員考試參考試題及答案解析
- 黑龍江高職單招語(yǔ)文試題附答案
- 高低壓配電安裝工程施工方案方案
- 2026年中國(guó)煙草專業(yè)知識(shí)考試題含答案
- 2026云南新華書(shū)店集團(tuán)限公司公開(kāi)招聘34人易考易錯(cuò)模擬試題(共500題)試卷后附參考答案
- 2026年人教版八年級(jí)語(yǔ)文上冊(cè)期末考試卷含答案
- 造紙業(yè)五年環(huán)?;?025年竹漿環(huán)保再生紙行業(yè)報(bào)告
- GB/T 17587.2-2025滾珠絲杠副第2部分:公稱直徑、公稱導(dǎo)程、螺母尺寸和安裝螺栓公制系列
- 鍋爐應(yīng)急預(yù)案演練(3篇)
評(píng)論
0/150
提交評(píng)論