maven将本地jar打包进入项目

本文介绍如何在Maven项目中引入本地的Jar包,并确保这些Jar包能在项目打包时一同被打包进去,避免运行时报错。具体步骤包括:在项目根目录下创建lib目录并放置Jar包,修改pom.xml文件引入本地Jar包,以及配置插件将本地Jar包包含在最终的项目打包中。

一、将本地jar包放入到项目中
在项目根目录下创建lib目录,将jar包放入到lib目录
在这里插入图片描述

二、在pom.xml引入本地jar包
groupId、artfactId可以自定义名称,systemPath为本地jar的绝对路径;
在这里插入图片描述

<dependency>
            <groupId>com.abc</groupId>
            <artifactId>TrustPayClient</artifactId>
            <version>V3.1.4</version>
            <scope>system</scope>
            <!--本地jar的路径,相对或者绝对都可以-->
            <systemPath>${project.basedir}/lib/TrustPayClient-V3.1.4.jar</systemPath>
        </dependency>

三、项目打包时将本地jar打包进入项目
如果没有增加如下配置,在编码时可以正常的引入第三方jar包中的类,但是在程序运行时会报错,通过以下配置,在打包maven项目时,本地的jar也会随之一起打包进入项目;
在这里插入图片描述

<!-- 将本地jar打包进项目中 -->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-war-plugin</artifactId>
                <version>2.3</version>
                <configuration>
                    <warName>${project.artifactId}</warName>
                    <webResources>
                        <resource>
                            <directory>lib/</directory>
                            <targetPath>WEB-INF/lib</targetPath>
                            <includes>
                                <include>**/*.jar</include>
                            </includes>
                        </resource>
                    </webResources>
                </configuration>
            </plugin>
<think>根据用户需求,用户希望将自定义的JAR文件打包到SpringBoot项目的最终可执行JAR中,并在启动时加载这些JAR。同时,用户提到了`resources/lib`目录,因此我们需要考虑如何将位于`src/main/resources/lib/`下的自定义JAR文件包含到可执行JAR中,并确保在运行时能够加载。分析问题:1.打包:需要将自定义JAR文件打包到最终的可执行JAR中。通常,SpringBoot的Maven插件会将依赖打包到一个可执行的JAR中,但自定义的JAR文件不是通过Maven仓库引入的,而是放在项目的`resources/lib`目录下。2.加载:在启动时,需要能够加载这些JAR文件中的类。解决方案:参考引用的内容,我们可以采用以下步骤:步骤1:将自定义JAR文件放置在`src/main/resources/lib/`目录下。步骤2:在`pom.xml`中通过`system`作用域依赖引入这些JAR。步骤3:配置Maven资源插件,确保在打包时包含这些JAR文件。步骤4:配置SpringBootMaven插件,使其在打包时包含`system`作用域的依赖。但是,需要注意的是,SpringBoot的可执行JAR在启动时不会自动加载`BOOT-INF/lib/`之外的JAR文件。因此,即使我们将自定义JAR打包到了可执行JAR中(例如放在`BOOT-INF/classes/lib/`下),默认情况下也不会被加载。因此,我们还需要在程序启动时动态加载这些JAR。可以通过在启动类中编写代码,从classpath中读取这些JAR文件,并将它们添加到类加载器中。详细步骤:1.项目结构:将自定义的JAR文件放入`src/main/resources/lib/`目录下。2.在`pom.xml`中添加依赖(以`sdk.jar`为例):```xml<dependency><groupId>com.jd</groupId><artifactId>sdk</artifactId><version>2.0</version><scope>system</scope><systemPath>${project.basedir}/src/main/resources/lib/sdk.jar</systemPath></dependency>```3.配置Maven资源插件,确保`resources/lib`目录下的JAR文件被打包到最终的JAR中:```xml<build><resources><resource><directory>src/main/resources</directory><includes><include>**/*</include></includes><filtering>true</filtering></resource></resources><!--其他配置--></build>```4.配置SpringBootMaven插件,使其包含`system`作用域的依赖(默认不包含):```xml<build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId><configuration><includeSystemScope>true</includeSystemScope></configuration></plugin></plugins></build>```5.在应用程序启动时加载这些JAR:在SpringBoot的启动类中,我们可以通过实现`ApplicationRunner`或`CommandLineRunner`接口,在应用启动后执行一段代码来加载这些JAR。但是,更合适的时机是在应用启动的最开始,因此我们可以编写一个静态块或者在`main`方法中加载。但是注意:由于这些JAR在classpath中(位于`BOOT-INF/classes/lib/`),我们可以通过类加载器获取资源,然后使用`URLClassLoader`来加载。然而,由于Java不允许在运行时直接扩展系统类加载器的类路径(特别是在Java9之后的模块化系统中),我们需要使用自定义类加载器或者反射机制来将URL添加到系统类加载器。这里,我们使用反射机制将JAR文件添加到系统类加载器中。注意:这种方法在Java9及以上版本可能受到限制,但在Java8中有效。在启动类中添加以下代码(在`main`方法中):```javapublicstaticvoidmain(String[]args){try{//获取系统类加载器ClassLoaderclassLoader=ClassLoader.getSystemClassLoader();//获取URLClassLoader的addURL方法Methodmethod=URLClassLoader.class.getDeclaredMethod("addURL",URL.class);method.setAccessible(true);//从classpath中读取lib目录下的所有JAR文件StringlibPath="lib/";Enumeration<URL>resources=classLoader.getResources(libPath);while(resources.hasMoreElements()){URLresource=resources.nextElement();//处理资源URL,如果是jar包内的资源,则转换为JarURLif(resource.getProtocol().equals("jar")){//转换为JarURL并获取实际路径JarURLConnectionjarConnection=(JarURLConnection)resource.openConnection();JarFilejarFile=jarConnection.getJarFile();//遍历JarFile中的条目,找到lib目录下的JAR文件Enumeration<JarEntry>entries=jarFile.entries();while(entries.hasMoreElements()){JarEntryentry=entries.nextElement();Stringname=entry.getName();if(name.startsWith(libPath)&&name.endsWith(".jar")){//构造JAR文件的URLURLjarUrl=newURL("jar:file:"+jarFile.getName()+"!/"+name);method.invoke(classLoader,jarUrl);}}}elseif(resource.getProtocol().equals("file")){//在IDE中运行时,可能是文件路径Filedir=newFile(resource.toURI());for(Filefile:dir.listFiles()){if(file.getName().endsWith(".jar")){method.invoke(classLoader,file.toURI().toURL());}}}}}catch(Exceptione){e.printStackTrace();}//启动SpringBoot应用SpringApplication.run(Application.class,args);}```但是,请注意,上面的代码比较复杂,且处理了两种环境:IDE运行(文件协议)和打包后运行(jar协议)。此外,在打包后运行时,我们无法直接访问JAR文件内的嵌套JAR作为文件,因此我们使用`jar:file`协议构造URL。然而,上述方法在SpringBoot的可执行JAR中可能无法直接加载嵌套JAR中的嵌套JAR(即`BOOT-INF/classes/lib/`下的JAR),因为Java类加载器并不支持直接加载嵌套在JAR中的JAR。因此,另一种做法是在启动前将这些JAR提取到临时目录,然后加载。SpringBoot的`org.springframework.boot.loader.LaunchedURLClassLoader`支持加载嵌套的JAR,但它主要用于加载`BOOT-INF/lib`下的依赖。我们可以利用SpringBoot的`Launcher`机制。实际上,SpringBoot提供了`PropertiesLauncher`,它支持通过`loader.path`属性来指定额外的类路径(包括目录和JAR文件)。我们可以使用`PropertiesLauncher`来启动应用,并设置`loader.path`为`lib/`(即我们自定义JAR所在的路径)。步骤:1.配置SpringBootMaven插件使用`PropertiesLauncher`:```xml<plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId><configuration><includeSystemScope>true</includeSystemScope><layout>ZIP</layout><!--使用PropertiesLauncher需要ZIP布局--></configuration></plugin>```2.在`application.properties`中设置(或者通过命令行参数):```propertiesloader.path=lib/```3.这样,在启动时,`PropertiesLauncher`会自动加载`lib/`目录下的所有JAR文件。因此,更推荐使用`PropertiesLauncher`的方式。总结步骤:1.将自定义JAR放在`src/main/resources/lib/`。2.在`pom.xml`中以`system`作用域依赖引入。3.配置Maven资源插件,确保资源被包含。4.配置SpringBootMaven插件使用`ZIP`布局(即`PropertiesLauncher`)并包含`system`作用域。5.不需要在代码中手动加载,而是通过`PropertiesLauncher`在启动时自动加载。注意:如果使用`PropertiesLauncher`,则启动命令无需特殊设置,因为我们在`application.properties`中设置了`loader.path=lib/`。但是,如果不想在配置文件中设置,也可以在启动命令中指定:```shelljava-Dloader.path=lib/-jaryour-application.jar```因此,我们选择第二种方案(使用PropertiesLauncher)更为简单可靠。完整配置示例:`pom.xml`配置:```xml<build><resources><resource><directory>src/main/resources</directory><includes><include>**/*</include></includes><filtering>true</filtering></resource></resources><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId><configuration><includeSystemScope>true</includeSystemScope><layout>ZIP</layout></configuration></plugin></plugins></build>```依赖配置(示例):```xml<dependencies><!--其他依赖--><dependency><groupId>com.jd</groupId><artifactId>sdk</artifactId><version>2.0</version><scope>system</scope><systemPath>${project.basedir}/src/main/resources/lib/sdk.jar</systemPath></dependency></dependencies>```在`application.properties`中添加:```propertiesloader.path=lib/```这样,在打包后,运行可执行JAR时,`PropertiesLauncher`会自动加载`lib/`目录下的所有JAR文件。注意:在开发环境(IDE中)运行,由于`lib/`目录在classpath下,`PropertiesLauncher`也会尝试加载,但是IDE可能不会将`lib`目录下的JAR作为依赖,因此开发环境中可能需要单独将这些JAR添加到类路径(例如在IDEA中,可以将`lib`目录标记为ResourcesRoot,并确保在运行配置的classpath中包含这些JAR)。或者,在开发环境中,我们仍然使用`spring-boot-maven-plugin`的默认布局(即不指定layout,使用默认的JAR布局),然后通过上述反射代码加载。但这样会导致开发环境和生产环境不一致。因此,为了简化,建议在开发环境中也使用`PropertiesLauncher`,可以在IDE的启动配置中添加VM参数:```-Dloader.path=lib/```并在IDE中将`src/main/resources/lib`目录下的JAR添加到模块的依赖中(如果IDE不支持自动添加,可以手动添加)。或者,我们可以在开发环境中避免使用`PropertiesLauncher`,而是通过Maven将自定义JAR作为依赖引入(作用域为`system`),这样在IDE中运行时会自动在类路径中。而生产环境使用`PropertiesLauncher`加载打包JAR内的`lib`下的JAR。由于在开发环境中,我们通过`system`作用域依赖已经将自定义JAR加入到classpath,因此不需要额外加载。在生产环境中,由于我们打包后这些JAR位于可执行JAR内部的`BOOT-INF/classes/lib/`下,通过`PropertiesLauncher`的`loader.path`可以加载。所以,在开发环境中,我们仍然使用默认的启动方式(即使用`org.springframework.boot.loader.JarLauncher`)在IDE中运行,而生产环境使用`PropertiesLauncher`。但是,在IDE中运行主类时,由于我们并没有将`lib`下的JAR作为依赖添加到IDE的运行配置中,所以需要手动添加。为了避免开发和生产环境的差异,我们可以在开发环境也使用`PropertiesLauncher`,通过配置IDE的启动参数。在IDEA中配置运行主类为`org.springframework.boot.loader.PropertiesLauncher`,并设置类路径包含自定义JAR。但这样比较麻烦。因此,另一种做法是:在开发环境中,我们通过Maven的`system`作用域依赖,IDE会自动将这些JAR添加到classpath(只要IDE正确识别了Maven项目)。这样,在开发环境中,我们不需要`PropertiesLauncher`,也不需要在代码中加载,因为JAR已经在classpath中。在生产环境中,我们使用`PropertiesLauncher`加载打包在可执行JAR内部的`lib`下的JAR。但是,在开发环境中,这些JAR是通过文件系统路径直接引入的,而在生产环境中,它们位于可执行JAR的内部。因此,我们需要确保生产环境能够正确加载。综上所述,我们采用以下方案:1.在`pom.xml`中配置`system`作用域依赖,指向`src/main/resources/lib/`下的JAR。2.配置SpringBootMaven插件使用`ZIP`布局(即`PropertiesLauncher`),并包含`system`作用域依赖。3.在`application.properties`中设置`loader.path=lib/`。4.在开发环境中,依赖Maven和IDE的集成,确保自定义JAR被添加到classpath(在IDEA中,通常会自动处理`system`作用域的依赖,但需要确认)。5.在生产环境(打包后的JAR)中,通过`PropertiesLauncher`加载`lib/`下的JAR。这样,开发环境和生产环境都能正常加载自定义JAR。最后,需要注意的是,如果自定义JAR文件较多,在`pom.xml`中逐个声明会比较繁琐。如果不想在`pom.xml`中逐个声明,可以考虑使用Maven插件在编译时将`lib`下的所有JAR添加为`system`作用域的依赖,但这比较复杂。因此,对于少量自定义JAR,推荐手动声明。如果有很多自定义JAR,可以考虑使用Maven的`antrun`插件或者编写一个自定义插件来动态添加依赖,但这超出了本问题的范围。因此,用户需要手动在`pom.xml`中为每个自定义JAR添加依赖。总结:按照上述步骤配置,即可实现将自定义JAR打包到SpringBoot可执行JAR中,并在启动时加载。相关问题:1.如何解决在开发环境中(如IDEA)运行SpringBoot应用时加载自定义JAR的问题?2.除了使用`PropertiesLauncher`,还有哪些方法可以加载嵌套在JAR中的JAR文件?3.如果自定义JAR文件很多,有没有自动化的方法在`pom.xml`中引入?</think>### 将自定义 JAR 打包到 Spring Boot 可执行 JAR 并在启动时加载 以下是实现该需求的完整解决方案,结合引用内容和最佳实践: #### 步骤 1:项目结构配置 ```bash src/main/resources └── lib/ # 存放自定义 JAR 文件 ├── custom1.jar └── custom2.jar ``` #### 步骤 2:`pom.xml` 关键配置 ```xml <dependencies> <!-- 声明自定义 JAR 依赖 --> <dependency> <groupId>com.example</groupId> <artifactId>custom-sdk</artifactId> <version>1.0.0</version> <scope>system</scope> <systemPath>${project.basedir}/src/main/resources/lib/custom1.jar</systemPath> </dependency> </dependencies> <build> <!-- 确保 resources/lib打包 --> <resources> <resource> <directory>src/main/resources</directory> <includes> <include>**/*.jar</include> <!-- 包含所有 JAR 文件 --> <include>**/*</include> <!-- 包含其他资源 --> </includes> <filtering>true</filtering> </resource> </resources> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <configuration> <!-- 关键:包含 system 作用域依赖 --> <includeSystemScope>true</includeSystemScope> </configuration> </plugin> </plugins> </build> ``` #### 步骤 3:运行时动态加载(Java 代码) 在启动类中添加 JAR 加载逻辑: ```java import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import java.net.URL; import java.net.URLClassLoader; import java.nio.file.*; @SpringBootApplication public class Application { public static void main(String[] args) throws Exception { // 动态加载 resources/lib 下的 JAR loadExternalJars(); SpringApplication.run(Application.class, args); } private static void loadExternalJars() throws Exception { Path libDir = Paths.get(Application.class.getResource("/lib").toURI()); URLClassLoader classLoader = (URLClassLoader) ClassLoader.getSystemClassLoader(); try (DirectoryStream<Path> stream = Files.newDirectoryStream(libDir, "*.jar")) { for (Path jar : stream) { URL jarUrl = jar.toUri().toURL(); // 反射注入到系统类加载器 java.lang.reflect.Method method = URLClassLoader.class .getDeclaredMethod("addURL", URL.class); method.setAccessible(true); method.invoke(classLoader, jarUrl); System.out.println("Loaded JAR: " + jar.getFileName()); } } } } ``` #### 关键配置说明 1. **`<includeSystemScope>true</includeSystemScope>`** 强制 Spring Boot 插件打包 `system` 作用域的依赖 [^1][^3] 2. **资源包含配置** ```xml <includes> <include>**/*.jar</include> <include>**/*</include> </includes> ``` 确保 `resources/lib` 下的所有文件(包括 JAR)被打包到最终 JAR 的 `BOOT-INF/classes/lib/` 中 [^2] 3. **动态加载原理** - 使用反射机制将 JAR 注入系统类加载器 - 路径定位:`getResource("/lib")` 指向打包JAR 内的 `BOOT-INF/classes/lib` - 支持加载多个 JAR 文件 #### 验证方法 1. 打包命令: ```bash mvn clean package ``` 2. 检查生成的可执行 JAR: ```bash jar tf target/your-app.jar | grep BOOT-INF/classes/lib ``` 应输出: ``` BOOT-INF/classes/lib/custom1.jar BOOT-INF/classes/lib/custom2.jar ``` 3. 启动应用时观察日志: ``` Loaded JAR: custom1.jar Loaded JAR: custom2.jar ``` #### 注意事项 1. **开发环境兼容** 在 IDE 中运行时,需确保 `src/main/resources/lib` 被标记为资源目录 2. **类加载顺序** 动态加载需在 Spring 上下文初始化前完成 3. **Java 模块化限制** 若使用 Java 9+ 模块系统,需在 `module-info.java` 中添加: ```java opens com.yourpackage to spring.core, spring.beans; ``` 4. **依赖冲突** 当自定义 JAR 与 Spring Boot 依赖冲突时,可使用 `<exclusions>` 排除冲突包 --- ### 相关问题 1. **如何解决 Spring Boot 打包后找不到 `resources/` 下配置文件的问题?** > 需在 `pom.xml` 中显式配置资源包含: > ```xml > <resources> > <resource> > <directory>src/main/resources</directory> > <includes> > <include>**/*.xml</include> > <include>**/*.properties</include> > </includes> > </resource> > </resources> > ``` > 否则 Maven 默认只打包特定类型文件 [^2] 2. **不修改 `pom.xml` 能否加载自定义 JAR?** > 可替代方案: > - 将 JAR 放入 `src/main/webapp/WEB-INF/lib/` 并使用 `@ServletComponentScan` > - 通过 `java -Dloader.path=lib/ -jar app.jar` 指定外部库路径 > 但会失去可执行 JAR 的单文件优势 3. **为什么需要反射修改类加载器?** > Java 的类加载器机制是层级封闭的: > - 系统类加载器默认不提供动态添加 URL 的 API > - 反射是突破此限制的标准做法 > - 在模块化系统中需额外开放权限 4. **如何调试类加载冲突?** > 启动时添加参数: > ```bash > java -jar your-app.jar --debug > ``` > 在日志中搜索: > ``` > DEBUG o.s.b.c.l.ClasspathLoggingApplicationListener - > Application started with classpath: [file:/.../custom1.jar...] > ``` 5. **是否支持嵌套 JAR 中的 JAR 加载?** > Spring Boot 2.3+ 支持 `jar:file:/app.jar!/BOOT-INF/classes!lib/custom.jar` 格式的嵌套 URL,但需自定义 `JarLauncher` 实现,推荐优先使用本文方案 [^1][^3] [^1]: 引用内容涉及 `system` 作用域依赖和打包配置 [^2]: 引用内容关于资源文件的打包处理 [^3]: 引用内容展示本地 JAR 依赖声明方式
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值