Spring Boot Maven项目如何分离应用Jar与依赖并生成可执行Jar
解决方案步骤
1. 配置Maven生成不含依赖的可执行Jar
不要直接移除spring-boot-maven-plugin,而是调整插件配置,让它只打包应用代码,同时用maven-dependency-plugin把依赖单独导出(后续上传到远程位置)。
修改pom.xml的插件配置:
<!-- 导出所有依赖到单独目录 --> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-dependency-plugin</artifactId> <executions> <execution> <id>copy-dependencies</id> <phase>package</phase> <goals> <goal>copy-dependencies</goal> </goals> <configuration> <!-- 依赖导出到target/dependencies目录 --> <outputDirectory>${project.build.directory}/dependencies</outputDirectory> <overWriteReleases>false</overWriteReleases> <overWriteSnapshots>false</overWriteSnapshots> <overWriteIfNewer>true</overWriteIfNewer> </configuration> </execution> </executions> </plugin> <!-- 生成可执行的轻量应用Jar,不包含依赖 --> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <configuration> <!-- 仅打包当前项目代码,排除所有第三方依赖 --> <includes> <include> <groupId>${project.groupId}</groupId> <artifactId>${project.artifactId}</artifactId> </include> </includes> <!-- 指定你的Spring Boot主类,确保Manifest包含Main-Class属性 --> <mainClass>com.yourpackage.YourApplicationMainClass</mainClass> </configuration> <executions> <execution> <goals> <goal>repackage</goal> </goals> </execution> </executions> </plugin>
执行mvn clean package后,会得到两个产物:
target/abc.jar:仅含应用代码的可执行Jar(体积约3MB)target/dependencies/:所有第三方依赖Jar,将这个目录下的文件上传到你的远程存储(如静态文件服务器、对象存储),得到远程根路径(例如http://your-remote-server/dependencies/)
2. 运行应用时加载远程依赖
方法一:直接通过URL类路径启动
假设远程依赖的根URL是http://your-remote-server/dependencies/,启动时将远程依赖的URL加入类路径:
# Linux/macOS系统用冒号分隔类路径 java -cp "target/abc.jar:http://your-remote-server/dependencies/*.jar" com.yourpackage.YourApplicationMainClass # Windows系统用分号分隔类路径 java -cp "target/abc.jar;http://your-remote-server/dependencies/*.jar" com.yourpackage.YourApplicationMainClass
如果依赖数量较多,手动写URL麻烦,可以先生成包含所有远程依赖URL的文本文件(比如deps-urls.txt),再通过@引用:
# 示例:生成依赖URL列表文件 echo "http://your-remote-server/dependencies/spring-boot-starter-web-3.2.0.jar" >> deps-urls.txt echo "http://your-remote-server/dependencies/spring-boot-autoconfigure-3.2.0.jar" >> deps-urls.txt # 补充其他依赖... # 启动应用 java -cp "target/abc.jar:@deps-urls.txt" com.yourpackage.YourApplicationMainClass
方法二:自定义类加载器(适合生产环境)
如果需要缓存远程依赖、动态更新版本等灵活逻辑,可以实现自定义类加载器,在应用启动前将远程依赖下载到本地临时目录,再加载:
public class YourApplicationMainClass { public static void main(String[] args) throws Exception { // 远程依赖根地址 String remoteDepRoot = "http://your-remote-server/dependencies/"; // 本地缓存目录 File cacheDir = new File(System.getProperty("java.io.tmpdir"), "app-deps"); cacheDir.mkdirs(); // 从配置文件或固定列表读取依赖Jar名称(需和编译版本一致) List<String> depJars = Arrays.asList( "spring-boot-starter-web-3.2.0.jar", "spring-boot-autoconfigure-3.2.0.jar" // 其他依赖... ); for (String jar : depJars) { URL remoteUrl = new URL(remoteDepRoot + jar); File localJar = new File(cacheDir, jar); // 本地无缓存时,下载远程Jar if (!localJar.exists()) { try (InputStream in = remoteUrl.openStream(); FileOutputStream out = new FileOutputStream(localJar)) { byte[] buffer = new byte[1024]; int len; while ((len = in.read(buffer)) != -1) { out.write(buffer, 0, len); } } } // 将本地缓存Jar加入类加载路径 URLClassLoader classLoader = new URLClassLoader( new URL[]{localJar.toURI().toURL()}, Thread.currentThread().getContextClassLoader() ); Thread.currentThread().setContextClassLoader(classLoader); } // 启动Spring Boot应用 SpringApplication.run(YourApplicationMainClass.class, args); } }
3. 关键注意事项
- 确保远程服务器的依赖文件可被应用访问(无权限限制、网络通畅)
- 远程依赖的版本必须和应用编译时的版本完全一致,避免兼容性问题
- 生产环境建议给远程依赖配置CDN或本地缓存,减少启动延迟
内容的提问来源于stack exchange,提问作者Mahesh
相关产品推荐
相关产品推荐

