<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
使用過SprongBoot
打過jar
包的都應該知道,目標檔案一般都會生成兩個檔案,一個是以.jar
的包,一個是.jar.original
檔案。那麼使用SpringBoot
會打出兩個包,而.jar.original
的作用是什麼呢?還有就是java -jar
是如何將一個SpringBoot
專案啟動,之間都進行了那些的操作?
其實.jar.original
是maven
在SpringBoot
重新打包之前的原始jar
包,內部只包含了專案的使用者類,不包含其他的依賴jar
包,生成之後,SpringBoot
重新打包之後,最後生成.jar
包,內部包含了原始jar
包以及其他的參照依賴。以下提及的jar
包都是SpringBoot
二次加工打的包。
SpringBoot
打出的jar
包,可以直接通過解壓的方式檢視內部的構造。一般情況下有三個目錄。
BOOT-INF
:這個資料夾下有兩個資料夾classes
用來存放使用者類,也就是原始jar.original
裡的類;還有一個是lib
,就是這個原始jar.original
參照的依賴。META-INF
:這裡是通過java -jar
啟動的入口資訊,記錄了入口類的位置等資訊。org
:Springboot loader
的程式碼,通過它來啟動。這裡主要介紹一下/BOOT-INF/MANIFEST.MF
檔案
Main-Class: org.springframework.boot.loader.JarLauncher Start-Class: cn.com.springboot.center.AuthEenterBootstrap
Main-Class
:記錄了java -jar
的啟動入口,當使用該命令啟動時就會呼叫這個入口類的main
方法,顯然可以看出,Springboot
轉移了啟動的入口,不是使用者編寫的xxx.xxx.BootStrap
的那個入口類。
Start-Class
:記錄了使用者編寫的xxx.xxx.BootStrap
的那個入口類,當內嵌的jar
包載入完成之後,會使用LaunchedURLClassLoader
執行緒載入類來載入這個使用者編寫的入口類。
3.1.1 Archive
歸檔檔案介面,實現迭代器介面,它有兩個子類,一個是JarFileArchive
對jar
包檔案使用,提供了返回這個jar
檔案對應的url
、或者這個jar
檔案的MANIFEST
檔案資料資訊等操作。是ExplodedArchive
是檔案目錄的使用也有獲取這個目錄url
的方法,以及獲取這個目錄下的所有Archive
檔案方法。
3.1.2 Launcher
啟動程式的基礎類別,這邊最後是通過JarLauncher#main()
來啟動。ExecutableArchiveLauncher
是抽象類,提供了獲取Start-Class
類路徑的方法,以及是否還有內嵌對應檔案的判斷方法和獲取到內嵌對應檔案集合的後置處理方法的抽象,由子類JarLauncher
和WarLauncher
自行實現。
3.1.3 Spring.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
物件。
從MANIFEST.MF
檔案中的Main-class
指向入口開始。
建立JarLauncher
並且通過它的launch()
方法開始載入jar
包內部資訊。
public static void main(String[] args) throws Exception { new JarLauncher().launch(args); }
JarLauncher
的空構造方法時一個空實現,剛開始看的時候還懵了一下,以為是在後續的操作中去載入的檔案,其實不然,在建立時由父類別ExecutableArchiveLauncher
的構造方法去載入的檔案。
載入為歸檔檔案物件:
this.archive = createArchive();
具體的載入方法:判斷路徑是否是一個資料夾,是則返回ExplodedArchive
物件,否則返回JarFileArchive
進入JarFileArchive
類:通過這個new
方法建立JarFile
物件
public class JarFileArchive implements Archive { public JarFileArchive(File file, URL url) throws IOException { this(new JarFile(file)); this.url = url; } }
進入到JarFile
方法:通過RandomAccessDataFile
讀取檔案的內容,並傳遞給本類中的方法進行具體的解析。
public class JarFile extends java.util.jar.JarFile { public JarFile(File file) throws IOException { this(new RandomAccessDataFile(file)); } }
進入jarLauncher
的launch
方法:註冊URL
協定的處理器,沒有指定時,預設指向org.springframework.boot.loader
包路徑,獲取類路徑下的歸檔檔案Archive
並通過這些歸檔檔案的URL
,建立執行緒上下文類載入器,使用類載入器和使用者編寫的啟動入口類,通過反射呼叫它的main
方法。
protected void launch(String[] args) throws Exception { JarFile.registerUrlProtocolHandler(); ClassLoader classLoader = createClassLoader(getClassPathArchives()); launch(args, getMainClass(), classLoader); }
JarLauncher
的getClassPathArchives
是在ExecutableArchiveLauncher
中實現:獲取歸檔檔案中滿足EntryFilterg
過濾器的項,isNestedArchive
方法由具體的之類實現。獲取到當前歸檔檔案下的所有子歸檔檔案之後的後置操作,是一個擴充套件點。在JarLauncher
中是一個空實現。
JarLauncher
的具體實現,這裡通過判斷是否在BOOT-INF/lib/
包下返回true
也就是說只會把jar
包下的BOOT-INF/lib/
下的檔案載入為Archive
物件
protected boolean isNestedArchive(Archive.Entry entry) { if (entry.isDirectory()) { return entry.getName().equals(BOOT_INF_CLASSES); } return entry.getName().startsWith(BOOT_INF_LIB); }
JarFileArchive
的getNestedArchives
方法:若匹配器匹配到則獲取內嵌歸檔檔案。
具體的獲取內嵌歸檔檔案邏輯:根據具體的Entry
物件,建立JarFile
物件並封裝成歸檔檔案物件後返回。
protected Archive getNestedArchive(Entry entry) throws IOException { try { JarFile jarFile = this.jarFile.getNestedJarFile(jarEntry); return new JarFileArchive(jarFile); } }
獲取到引數entry
對應的RandomAccessData
物件,這裡根據springboot
擴充套件的url
協定,在父路徑的基礎上新增!/
來標記子包。
private JarFile createJarFileFromFileEntry(JarEntry entry) throws IOException { RandomAccessData entryData = this.entries.getEntryData(entry.getName()); return new JarFile(this.rootFile, this.pathFromRoot + "!/" + entry.getName(), entryData, JarFileType.NESTED_JAR); }
到這基本上讀取jar
內部資訊,載入為對應歸檔檔案物件的大概過程已經講完了,接下來分析一下在獲取到了整個jar
的歸檔檔案物件後的處理。
通過歸檔檔案物件列表,獲取對應的url
資訊,並通過url
資訊建立LaunchedURLClassLoader
protected ClassLoader createClassLoader(List<Archive> archives) { List<URL> urls = new ArrayList<URL>(archives.size()); for (Archive archive : archives) { urls.add(archive.getUrl()); } return createClassLoader(urls.toArray(new URL[urls.size()])); }
獲取到對應的LaunchedUrlClassLoader
類載入器之後,設定執行緒的上下文類載入器為該載入器。根據MANIFI.MF
檔案中的start-classs
資訊建立專案啟動入口主類物件,並通過返回物件的run
方法啟動
protected void launch(String[] args, String mainClass, ClassLoader classLoader) { Thread.currentThread().setContextClassLoader(classLoader); createMainMethodRunner(mainClass, args, classLoader).run(); }
進入MainMethodRunner
的run
方法:先通過當前執行緒獲取到main
入口類,然後通過反射呼叫啟動專案啟動類的main
方法
public void run() throws Exception { Class<?> mainClass = Thread.currentThread().getContextClassLoader() .loadClass(this.mainClassName); Method mainMethod = mainClass.getDeclaredMethod("main", String[].class); mainMethod.invoke(null, new Object[] { this.args }); }
最後來說一下這個LaunchedURLClassLoader
,它繼承於URLClassLoader
,並重寫了loadClass
方法
LaunchedClassLoader
的loadClass
方法:呼叫父類別loadClass
方法,走正常委派流程,最終會被LaunchURLClassLoader
載入。
@Override protected Class<?> loadClass(String name, boolean resolve){ try { try { definePackageIfNecessary(name); } return super.loadClass(name, resolve); } }
進入URLClassLoader
中根據springboot
解析進行解析。根據名稱將路徑轉化為以.class
結尾的/
分隔的格式。通過UrlClassPath
物件根據路徑獲取資源類檔案
new PrivilegedExceptionAction<Class<?>>() { public Class<?> run() throws ClassNotFoundException { String path = name.replace('.', '/').concat(".class"); Resource res = ucp.getResource(path, false); if (res != null) { try { return defineClass(name, res); } } } }
Springboot
主要實現了對URL
載入方式進行了擴充套件,並且對一些物件Archive
、JarFile
、Entry
等進行了抽象和擴充套件,最後使用LaunchedUrlClassLoader
來進行處理。
到此這篇關於SpringBoot的jar包如何啟動的實現的文章就介紹到這了,更多相關SpringBoot jar包啟動內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45