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 也需要自定義加載很多類(lèi)順帶擴(kuò)展了一個(gè)參數(shù)出來(lái)
方案1
擴(kuò)大 -cp 由 AppClassLoader 幫我們加載外部 Jar
可以使用 classpath 指定類(lèi)加載的路徑,但 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 指定類(lèi)加載路徑加載其他 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 容器依賴(lài)位于 WEB-INF/lib-provided
Main-Class: org.springframework.boot.loader.WarLauncher
3、ZIP,即DIR,類(lèi)似于 JAR
Main-Class: org.springframework.boot.loader.PropertiesLauncher
4、MODULE,將所有的依賴(lài)庫(kù)打包(scope為provided的除外),但是不打包 Spring Boot 的任何Launcher
5、NONE,將所有的依賴(lài)庫(kù)打包,但是不打包 Spring Boot 的任何 Launcher
無(wú)論啟動(dòng)類(lèi)是 JarLauncher 或者 PropertiesLauncher,loader.path 引入的 Jar 和 Spring Boot jar 包中 BOOT-INFO/lib 包下 Jar 都是使用類(lèi)加載器 org.springframework.boot.loader.LaunchedURLClassLoader 進(jìn)行加載,也就是說(shuō)他們使用的是同一個(gè)類(lèi)加載器。這個(gè)類(lèi)加載器主要就是負(fù)責(zé)加載 Jar 包里的 Jar 的加載,因?yàn)镴DK沒(méi)有實(shí)現(xiàn)該功能所以 SpringBoot 定義了該類(lèi)
注意到同一個(gè)程序,打包成不同類(lèi)型時(shí),PropertiesLauncher (20s) 比 JarLauncher (8s) 啟動(dòng)慢很多。
方案3
自定義類(lèi)加載器,加載固定目錄下的jar包或者讀取環(huán)境變量路徑
這種方式需要程序啟動(dòng)的某個(gè)節(jié)點(diǎn),調(diào)用自定義類(lèi)加載器去加載指定目錄下的 Jar 包,時(shí)間點(diǎn)不是很好控制。但這個(gè)定制化程度比較高。
//可以在這里調(diào)用自定義類(lèi)加載 SpringApplication.run(SpringBootDemo.class, args);
方案4
通過(guò)設(shè)置-Xbootclasspath/a或者 Extention ClassLoader通過(guò)改變參數(shù)java.ext.dirs實(shí)現(xiàn)
會(huì)改變系統(tǒng)類(lèi)加載器加載行為不安全不推薦!??!
加載后的類(lèi)如何掃描進(jìn)入Spring容器
對(duì)于業(yè)務(wù) Jar 包類(lèi),可以預(yù)先在SpringBoot中指定好掃描包路徑,那么只需要插件包路徑是com.demo開(kāi)頭即可,如下
@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)裝配的類(lèi)即可如 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)文章
Java RSA加密工具類(lèi)的設(shè)計(jì)與實(shí)現(xiàn)詳解
RSA算法是一種常用的非對(duì)稱(chēng)加密算法,這篇文章主要為大家詳細(xì)介紹了如何通過(guò)Java編寫(xiě)一個(gè)RSA加密工具類(lèi),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2025-02-02
Java開(kāi)發(fā)學(xué)習(xí)之Bean的生命周期詳解
從創(chuàng)建到消亡的完整過(guò)程,例如人從出生到死亡的整個(gè)過(guò)程就是一個(gè)生命周期。本文將通過(guò)示例為大家詳細(xì)講講Bean的生命周期,感興趣的可以學(xué)習(xí)一下2022-06-06
Spring Security結(jié)合JWT的方法教程
這篇文章主要給大家介紹了關(guān)于Spring Security結(jié)合JWT的方法教程,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧。2017-12-12
SpringBoot集成FastDFS依賴(lài)實(shí)現(xiàn)文件上傳的示例
這篇文章主要介紹了SpringBoot集成FastDFS依賴(lài)實(shí)現(xiàn)文件上傳,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2021-05-05
基于MybatisPlus將百度天氣數(shù)據(jù)存儲(chǔ)至PostgreSQL數(shù)據(jù)庫(kù)
這篇文章主要為大家詳細(xì)介紹了如何基于MybatisPlus將百度天氣數(shù)據(jù)存儲(chǔ)至PostgreSQL數(shù)據(jù)庫(kù),文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2025-08-08
SpringBoot項(xiàng)目Jar包如何瘦身部署的實(shí)現(xiàn)
這篇文章主要介紹了SpringBoot項(xiàng)目Jar包如何瘦身部署的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-09-09
MyBatis復(fù)雜Sql查詢(xún)實(shí)現(xiàn)示例介紹
在利用mybatis做查詢(xún)的時(shí)候,一般返回結(jié)果用resulttype,這種情況必須是查詢(xún)的結(jié)果在對(duì)應(yīng) 的pojo類(lèi)中有對(duì)應(yīng)的,一般都是單表查詢(xún),但是對(duì)于一些復(fù)雜的情況,比如需要用到多表查詢(xún)的時(shí)候,resultType不再適用,此時(shí)一般用resultMap來(lái)表示返回的結(jié)果2022-12-12
Springboot工程中使用filter過(guò)程解析
這篇文章主要介紹了springboot工程中使用filter過(guò)程解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-03-03

