SpringBoot加載外部Jar實(shí)現(xiàn)功能按需擴(kuò)展
實(shí)現(xiàn)方案
實(shí)現(xiàn)這個(gè)很簡(jiǎn)單,只需要完成下面兩步:
- 想辦法將 Class 加載到 JVM
- 使 Spring 掃描到 Class
有時(shí)候java中的各種框架以及復(fù)雜的概念源碼給我們?cè)斐闪撕艽罄斫庹系K,特別是Spring家族的所以先想清楚大致實(shí)現(xiàn)步驟比較好
將Class加載到JVM
現(xiàn)在我們?cè)O(shè)定需要加載的 Jar 在 /user/local/java/plugins
目錄下,對(duì)于第 1 步,現(xiàn)在有如下幾種實(shí)現(xiàn)方式:
- 擴(kuò)大
-cp
由AppClassLoader
幫我們加載外部 Jar - 使用 SpringBoot 提供的啟動(dòng)參數(shù)
loader.path
實(shí)現(xiàn) - 自定義
classloader
實(shí)現(xiàn)加載指定位置的 Jar
其中 1 和 3 是JDK提供的方案,2是 SpringBoot 擴(kuò)展的方案,畢竟 SpringBoot 也需要自定義加載很多類順帶擴(kuò)展了一個(gè)參數(shù)出來(lái)
方案1
擴(kuò)大 -cp 由 AppClassLoader 幫我們加載外部 Jar
可以使用 classpath
指定類加載的路徑,但 classpath
的生效是有條件的,這里其實(shí)對(duì)應(yīng)了 Jar 包的兩種啟動(dòng)方式:通過(guò)Jar包里的Main函數(shù)啟動(dòng)或者運(yùn)行Jar啟動(dòng)
SpringBoot 打包后 MANIFEST.MF
內(nèi)容如下:
Manifest-Version: 1.0 Created-By: Maven JAR Plugin 3.2.2 Build-Jdk-Spec: 18 Implementation-Title: intelligent-soul Implementation-Version: 0.0.1-SNAPSHOT Main-Class: org.springframework.boot.loader.JarLauncher Start-Class: com.test.MyApplication Spring-Boot-Version: 2.6.15 Spring-Boot-Classes: BOOT-INF/classes/ Spring-Boot-Lib: BOOT-INF/lib/ Spring-Boot-Classpath-Index: BOOT-INF/classpath.idx Spring-Boot-Layers-Index: BOOT-INF/layers.idx
所以需要使用 Main 函數(shù)啟動(dòng)的方式,不能使用之前的常用的 Jar 包啟動(dòng)方式了。對(duì)于 SpringBoot 應(yīng)用 Main-Class
是 JarLauncher
所以此時(shí)啟動(dòng)命令要改成
java -cp /user/local/java/plugins org.springframework.boot.loader.JarLauncher
- 優(yōu)點(diǎn):實(shí)現(xiàn)簡(jiǎn)單
- 缺點(diǎn):每個(gè) Jar 包啟動(dòng)命令都一樣了,不好區(qū)分
方案2
使用SpringBoot擴(kuò)展的啟動(dòng)參數(shù),使用java -jar 配合Loader.path參數(shù)
因?yàn)?Spring Boot 程序大多是打成 Jar 包,使用 java -jar boot.jar
的方式啟動(dòng) (此時(shí) -cp
無(wú)效),可以使用 loader.path
指定類加載路徑加載其他 Jar,但 loader.path
生效也是有條件的:
SpringBoot 默認(rèn)打包方式的Main-Class
是JarLauncher
配置 Main-Class
為了使 loader.path
參數(shù)生效需要生成 Jar 包的 Main-Class
項(xiàng)配置為 PropertiesLauncher
,在 maven
中如下配置,可參考 Using the PropertiesLauncher
:
<build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <configuration> <!-- 打包時(shí)排除scope為system的包 --> <includeSystemScope>false</includeSystemScope> <!-- jvm啟動(dòng)時(shí)通過(guò)-Dloader.path加載包,必須指定layout為ZIP,否則-Dloader.path無(wú)效!??! --> <layout>ZIP</layout> </configuration> <executions> <execution> <goals> <goal>repackage</goal> </goals> </execution> </executions> </plugin> </plugins> <finalName>Test</finalName> </build>
其中 layout 可配置值如下:
1、JAR,即通常的可執(zhí)行 jar
Main-Class: org.springframework.boot.loader.JarLauncher
2、WAR,即通常的可執(zhí)行war,需要的 servlet 容器依賴位于 WEB-INF/lib-provided
Main-Class: org.springframework.boot.loader.WarLauncher
3、ZIP,即DIR,類似于 JAR
Main-Class: org.springframework.boot.loader.PropertiesLauncher
4、MODULE,將所有的依賴庫(kù)打包(scope
為provided
的除外),但是不打包 Spring Boot 的任何Launcher
5、NONE,將所有的依賴庫(kù)打包,但是不打包 Spring Boot 的任何 Launcher
無(wú)論啟動(dòng)類是 JarLauncher
或者 PropertiesLauncher
,loader.path
引入的 Jar 和 Spring Boot jar 包中 BOOT-INFO/lib
包下 Jar 都是使用類加載器 org.springframework.boot.loader.LaunchedURLClassLoader
進(jìn)行加載,也就是說(shuō)他們使用的是同一個(gè)類加載器。這個(gè)類加載器主要就是負(fù)責(zé)加載 Jar 包里的 Jar 的加載,因?yàn)镴DK沒(méi)有實(shí)現(xiàn)該功能所以 SpringBoot 定義了該類
注意到同一個(gè)程序,打包成不同類型時(shí),PropertiesLauncher (20s)
比 JarLauncher (8s)
啟動(dòng)慢很多。
方案3
自定義類加載器,加載固定目錄下的jar包或者讀取環(huán)境變量路徑
這種方式需要程序啟動(dòng)的某個(gè)節(jié)點(diǎn),調(diào)用自定義類加載器去加載指定目錄下的 Jar 包,時(shí)間點(diǎn)不是很好控制。但這個(gè)定制化程度比較高。
//可以在這里調(diào)用自定義類加載 SpringApplication.run(SpringBootDemo.class, args);
方案4
通過(guò)設(shè)置-Xbootclasspath/a或者 Extention ClassLoader通過(guò)改變參數(shù)java.ext.dirs實(shí)現(xiàn)
會(huì)改變系統(tǒng)類加載器加載行為不安全不推薦?。?!
加載后的類如何掃描進(jìn)入Spring容器
對(duì)于業(yè)務(wù) Jar 包類,可以預(yù)先在SpringBoot中指定好掃描包路徑,那么只需要插件包路徑是com.demo
開頭即可,如下
@SpringBootApplication(scanBasePackages = {"com.demo"}) public class SpringBootDemoApplication { public static void main(String[] args) { SpringApplication.run(SpringBootDemoApplication.class, args); }
如不符合包名前綴一致的情況,需要在jar包META-INF
下的spring.factories
指定好自動(dòng)裝配的類即可如 mybatis-plus:
# Auto Configure org.springframework.boot.env.EnvironmentPostProcessor=\ com.baomidou.mybatisplus.autoconfigure.SafetyEncryptProcessor org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ com.baomidou.mybatisplus.autoconfigure.IdentifierGeneratorAutoConfiguration,\ com.baomidou.mybatisplus.autoconfigure.MybatisPlusLanguageDriverAutoConfiguration,\ com.baomidou.mybatisplus.autoconfigure.MybatisPlusAutoConfiguration
到此這篇關(guān)于SpringBoot加載外部Jar實(shí)現(xiàn)功能按需擴(kuò)展的文章就介紹到這了,更多相關(guān)SpringBoot加載外部Jar內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
VerifyCodeServlet(一次性驗(yàn)證碼)
這篇文章主要介紹了VerifyCodeServlet一次性驗(yàn)證碼的使用方法2017-05-05SpringMVC中@controllerAdvice注解的詳細(xì)解釋
剛接觸SpringMVC應(yīng)該很少會(huì)見(jiàn)到這個(gè)注解,其實(shí)它的作用非常大,下面這篇文章主要給大家介紹了關(guān)于SpringMVC中@controllerAdvice注解的相關(guān)資料,需要的朋友可以參考下2022-02-02貨拉拉大數(shù)據(jù)對(duì)BitMap的探索實(shí)踐詳解
這篇文章主要為大家介紹了貨拉拉大數(shù)據(jù)對(duì)BitMap的探索實(shí)踐詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-09-09springboot配合Thymeleaf完美實(shí)現(xiàn)遍歷功能
Thymeleaf顯然是一個(gè)開發(fā)頁(yè)面的技術(shù),現(xiàn)在各種前端技術(shù)層出不窮,比如現(xiàn)在主流的Vue、React、AngularJS等。這篇文章主要介紹了springboot配合Thymeleaf完美實(shí)現(xiàn)遍歷,需要的朋友可以參考下2021-09-09解決fcitx輸入法在IDEA中輸入法候選框無(wú)法跟隨光標(biāo)移動(dòng)的問(wèn)題
這篇文章主要介紹了解決fcitx輸入法在Intellij IDEA開發(fā)工具中輸入法候選框無(wú)法跟隨光標(biāo)移動(dòng)的問(wèn)題,代碼簡(jiǎn)單易懂對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-10-10IDEA中springboot的熱加載thymeleaf靜態(tài)html頁(yè)面的方法
這篇文章主要介紹了IDEA中springboot的熱加載thymeleaf靜態(tài)html頁(yè)面的方法,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-07-07Java?數(shù)據(jù)結(jié)構(gòu)與算法系列精講之棧
棧(stack)又名堆棧,它是一種運(yùn)算受限的線性表。限定僅在表尾進(jìn)行插入和刪除操作的線性表。這一端被稱為棧頂,相對(duì)地,把另一端稱為棧底,棧是基礎(chǔ)中的基礎(chǔ),如果你還沒(méi)掌握透徹就來(lái)接著往下看吧2022-02-02