SpringBoot的jar包如何啟動的實現_第1頁
SpringBoot的jar包如何啟動的實現_第2頁
SpringBoot的jar包如何啟動的實現_第3頁
SpringBoot的jar包如何啟動的實現_第4頁
SpringBoot的jar包如何啟動的實現_第5頁
已閱讀5頁,還剩3頁未讀 繼續免費閱讀

下載本文檔

版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領

文檔簡介

第SpringBoot的jar包如何啟動的實現目錄一、簡介二、jar包的內部結構三、加載過程1.使用到的一些類2.過程分析四、總結

一、簡介

?使用過SprongBoot打過jar包的都應該知道,目標文件一般都會生成兩個文件,一個是以.jar的包,一個是.jar.original文件。那么使用SpringBoot會打出兩個包,而.jar.original的作用是什么呢?還有就是java-jar是如何將一個SpringBoot項目啟動,之間都進行了那些的操作?

?其實.jar.original是maven在SpringBoot重新打包之前的原始jar包,內部只包含了項目的用戶類,不包含其他的依賴jar包,生成之后,SpringBoot重新打包之后,最后生成.jar包,內部包含了原始jar包以及其他的引用依賴。以下提及的jar包都是SpringBoot二次加工打的包。

二、jar包的內部結構

SpringBoot打出的jar包,可以直接通過解壓的方式查看內部的構造。一般情況下有三個目錄。

BOOT-INF:這個文件夾下有兩個文件夾classes用來存放用戶類,也就是原始jar.original里的類;還有一個是lib,就是這個原始jar.original引用的依賴。META-INF:這里是通過java-jar啟動的入口信息,記錄了入口類的位置等信息。org:Springbootloader的代碼,通過它來啟動。

這里主要介紹一下/BOOT-INF/MANIFEST.MF文件

Main-Class:org.springframework.boot.loader.JarLauncher

Start-Class:.springboot.center.AuthEenterBootstrap

Main-Class:記錄了java-jar的啟動入口,當使用該命令啟動時就會調用這個入口類的main方法,顯然可以看出,Springboot轉移了啟動的入口,不是用戶編寫的xxx.xxx.BootStrap的那個入口類。

Start-Class:記錄了用戶編寫的xxx.xxx.BootStrap的那個入口類,當內嵌的jar包加載完成之后,會使用LaunchedURLClassLoader線程加載類來加載這個用戶編寫的入口類。

三、加載過程

1.使用到的一些類

3.1.1Archive

?歸檔文件接口,實現迭代器接口,它有兩個子類,一個是JarFileArchive對jar包文件使用,提供了返回這個jar文件對應的url、或者這個jar文件的MANIFEST文件數據信息等操作。是ExplodedArchive是文件目錄的使用也有獲取這個目錄url的方法,以及獲取這個目錄下的所有Archive文件方法。

3.1.2Launcher

?啟動程序的基類,這邊最后是通過JarLauncher#main()來啟動。ExecutableArchiveLauncher是抽象類,提供了獲取Start-Class類路徑的方法,以及是否還有內嵌對應文件的判斷方法和獲取到內嵌對應文件集合的后置處理方法的抽象,由子類JarLauncher和WarLauncher自行實現。

3.1.3Spring.loader下的JarFile和JarEntry

?jarFile繼承于jar.util.jar.JarFile,JarEntry繼承于java.util.jar.JarEntry,對原始的一些方法進行重寫覆蓋。每一個JarFileArchive都擁有一個JarFile方法,用于存儲這個jar包對應的文件,而每一個JarFile都有一個JarFileEntries,JarFileEntries是一個迭代器。總的來說,在解析jar包時,會將jar包內的文件封裝成JarEntry對象后由JarFile對象保存文件列表的迭代器。所以JarFileArchive和JarFileEntries之間是通過JarFile連接,二者都可以獲取到JarFile對象。

2.過程分析

從MANIFEST.MF文件中的Main-class指向入口開始。

創建JarLauncher并且通過它的launch()方法開始加載jar包內部信息。

publicstaticvoidmain(String[]args)throwsException{

newJarLauncher().launch(args);

}

JarLauncher的空構造方法時一個空實現,剛開始看的時候還懵了一下,以為是在后續的操作中去加載的文件,其實不然,在創建時由父類ExecutableArchiveLauncher的構造方法去加載的文件。

加載為歸檔文件對象:

this.archive=createArchive();

具體的加載方法:判斷路徑是否是一個文件夾,是則返回ExplodedArchive對象,否則返回JarFileArchive進入JarFileArchive類:通過這個new方法創建JarFile對象

publicclassJarFileArchiveimplementsArchive{

publicJarFileArchive(Filefile,URLurl)throwsIOException{

this(newJarFile(file));

this.url=url;

}

進入到JarFile方法:通過RandomAccessDataFile讀取文件的內容,并傳遞給本類中的方法進行具體的解析。

publicclassJarFileextendsjava.util.jar.JarFile{

publicJarFile(Filefile)throwsIOException{

this(newRandomAccessDataFile(file));

}

進入jarLauncher的launch方法:注冊URL協議的處理器,沒有指定時,默認指向org.springframework.boot.loader包路徑,獲取類路徑下的歸檔文件Archive并通過這些歸檔文件的URL,創建線程上下文類加載器,使用類加載器和用戶編寫的啟動入口類,通過反射調用它的main方法。

protectedvoidlaunch(String[]args)throwsException{

JarFile.registerUrlProtocolHandler();

ClassLoaderclassLoader=createClassLoader(getClassPathArchives());

launch(args,getMainClass(),classLoader);

}

JarLauncher的getClassPathArchives是在ExecutableArchiveLauncher中實現:獲取歸檔文件中滿足EntryFilterg過濾器的項,isNestedArchive方法由具體的之類實現。獲取到當前歸檔文件下的所有子歸檔文件之后的后置操作,是一個擴展點。在JarLauncher中是一個空實現。

JarLauncher的具體實現,這里通過判斷是否在BOOT-INF/lib/包下返回true也就是說只會把jar包下的BOOT-INF/lib/下的文件加載為Archive對象

protectedbooleanisNestedArchive(Archive.Entryentry){

if(entry.isDirectory()){

returnentry.getName().equals(BOOT_INF_CLASSES);

returnentry.getName().startsWith(BOOT_INF_LIB);

}

JarFileArchive的getNestedArchives方法:若匹配器匹配到則獲取內嵌歸檔文件。

具體的獲取內嵌歸檔文件邏輯:根據具體的Entry對象,創建JarFile對象并封裝成歸檔文件對象后返回。

protectedArchivegetNestedArchive(Entryentry)throwsIOException{

try{

JarFilejarFile=this.jarFile.getNestedJarFile(jarEntry);

returnnewJarFileArchive(jarFile);

}

獲取到參數entry對應的RandomAccessData對象,這里根據springboot擴展的url協議,在父路徑的基礎上添加!/來標記子包。

privateJarFilecreateJarFileFromFileEntry(JarEntryentry)throwsIOException{

RandomAccessDataentryData=this.entries.getEntryData(entry.getName());

returnnewJarFile(this.rootFile,this.pathFromRoot+"!/"+entry.getName(),

entryData,JarFileType.NESTED_JAR);

}

到這基本上讀取jar內部信息,加載為對應歸檔文件對象的大概過程已經講完了,接下來分析一下在獲取到了整個jar的歸檔文件對象后的處理。

通過歸檔文件對象列表,獲取對應的url信息,并通過url信息創建LaunchedURLClassLoader

protectedClassLoadercreateClassLoader(ListArchivearchives){

ListURLurls=newArrayListURL(archives.size());

for(Archivearchive:archives){

urls.add(archive.getUrl());

returncreateClassLoader(urls.toArray(newURL[urls.size()]));

}

獲取到對應的LaunchedUrlClassLoader類加載器之后,設置線程的上下文類加載器為該加載器。根據MANIFI.MF文件中的start-classs信息創建項目啟動入口主類對象,并通過返回對象的run方法啟動

protectedvoidlaunch(String[]args,StringmainClass,ClassLoaderclassLoader){

Thread.currentThread().setContextClassLoader(classLoader);

createMainMethodRunner(mainClass,args,classLoader).run();

}

進入MainMethodRunner的run方法:先通過當前線程獲取到main入口類,然后通過反射調用啟動項目啟動類的main方法

publicvoidrun()throwsException{

ClassmainClass=Thread.currentThread().getContextClassLoader()

.loadClass(this.mainClassName);

MethodmainMethod=mainClass.getDeclaredMethod("main",String[].class);

mainMethod.invoke(null,newObject[]{this.args});

}

最后來說一下這個LaunchedURLClassLoader,它繼承于URLClassLoader,并重寫了loadClass方法

LaunchedClassLoader的loadClass方法:調用父類loadClass方法,走正常委派流程,最終會被LaunchURLClassLoader加載。

@Override

protectedClassloadClass(Stringname,booleanresolve){

try{

try{

definePackageIfNecessary(name);

returnsuper.loadClass(name,resolve);

}

進入URLClassLoader中根據springboot解析進行解析。根據名稱將路徑轉化為以.class結尾的/分隔的格式。通過UrlClassPath對象根據路徑獲取資源類文件

newPrivilegedExceptionActionClass(){

publicClassrun()throwsClassNotFoundExcep

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯系上傳者。文件的所有權益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網頁內容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
  • 4. 未經權益所有人同意不得將文件中的內容挪作商業或盈利用途。
  • 5. 人人文庫網僅提供信息存儲空間,僅對用戶上傳內容的表現方式做保護處理,對用戶上傳分享的文檔內容本身不做任何修改或編輯,并不能對任何下載內容負責。
  • 6. 下載文件中如有侵權或不適當內容,請與我們聯系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論