
系统梳理Maven打包的5种方式手把手教你实现依赖分离、配置外置并深入剖析Spring Boot Starter的正确打包姿势。作者介绍大家好我是CodeStats。一个在底层技术上“考古”了四年的硬核爱好者也是WWAIC全周项目AI编程范式的提出者和实践者。我曾手写过一个完整的Java Web框架从IoC容器到嵌入式Tomcat代码全开源也喜欢用通俗的语言拆解CPU、JVM、操作系统的运行本质。我的技术信条所有高深的技术最后都能用大白话讲清楚。如果讲不清楚说明还没真正理解。读完本文你能收获什么✅ 彻底搞懂常规JAR与Fat JAR的本质区别✅ 掌握Maven5种主流打包方式及其适用场景✅ 学会将依赖包分离到lib目录并正确配置Class-Path✅ 理解Spring Boot Starter应该用什么方式打包✅ 掌握配置文件外置的完整方案与优先级规则目录提问一常规JAR包和Fat JAR有何区别有哪些打包方式提问二如何将依赖包和主包区分开依赖包放lib目录如何指定Class-Path提问三自定义Spring Boot Starter作为依赖给其他项目引用应该用哪种打包方式提问四Spring Boot Fat JAR启动时配置文件的加载顺序和优先级是什么提问五独立JAR包如何排除配置文件配置文件和依赖lib包放在什么位置才能被正确加载提问一常规JAR包和Fat JAR有何区别有哪些打包方式1.1 本质区别对比维度常规JAR普通JARFat JARUber JAR / Shaded JAR包含内容仅包含当前项目编译后的class文件包含项目代码 所有第三方依赖Spring、连接池等体积小几十KB~几MB大几十MB~上百MB启动方式需指定classpath加载依赖java -jar直接运行适用场景作为库供其他项目引用作为独立应用部署运行1.2 Maven的5种打包方式Maven生态中主要有以下几种打包插件打包方式核心插件特点适用场景① 普通JARmaven-jar-plugin只打包项目自身class不含依赖库项目、Starter、公共模块② Fat JARShademaven-shade-plugin将所有依赖合并成一个JAR可重命名包名解决冲突需要解决依赖冲突、合并资源的场景③ Fat JARAssemblymaven-assembly-plugin支持自定义打包结构可将依赖打包进JAR或单独存放需要定制化打包结构的场景④ Spring Boot Fat JARspring-boot-maven-pluginSpring Boot专属生成可直接运行的Fat JARSpring Boot应用部署⑤ Thin JAR瘦包自定义或spring-boot-thin-launcher只包含项目代码依赖单独管理依赖频繁变化、希望减小传输体积的场景核心认知maven-jar-plugin打的是“普通JAR”spring-boot-maven-plugin是在前者基础上做“重打包repackage”生成可执行Fat JAR。提问二如何将依赖包和主包区分开依赖包放lib目录如何指定Class-Path2.1 核心思路将依赖分离到lib/目录的本质是让JAR的MANIFEST.MF文件告诉JVM去哪里找依赖。2.2 完整Maven配置xmlbuild plugins !-- 1. 生成主JAR指定Class-Path指向lib目录 -- plugin groupIdorg.apache.maven.plugins/groupId artifactIdmaven-jar-plugin/artifactId version3.2.2/version configuration outputDirectory${project.basedir}/outputDirectory archive manifest addClasspathtrue/addClasspath !-- 自动生成Class-Path -- classpathPrefixlib//classpathPrefix !-- 依赖前缀lib/ -- mainClasscom.example.MyApp/mainClass !-- 启动类 -- /manifest /archive /configuration /plugin !-- 2. 复制所有依赖到lib目录 -- plugin groupIdorg.apache.maven.plugins/groupId artifactIdmaven-dependency-plugin/artifactId version3.5.0/version executions execution idcopy-dependencies/id phasepackage/phase goals goalcopy-dependencies/goal /goals configuration outputDirectory${project.basedir}/lib/outputDirectory includeScopecompile/includeScope /configuration /execution /executions /plugin /plugins /build2.3 关键参数说明参数作用示例addClasspath是否在MANIFEST中生成Class-Path条目trueclasspathPrefix所有依赖JAR的路径前缀lib/outputDirectorydependency-plugin依赖复制目标目录${project.basedir}/lib2.4 最终目录结构text项目根目录/ ├── myapp.jar # 主JAR不含依赖 ├── lib/ # 所有依赖JAR │ ├── spring-core-xxx.jar │ ├── spring-boot-xxx.jar │ └── ... └── application.yml # 外部配置文件启动时JVM会自动读取MANIFEST中的Class-Path: lib/xxx.jar加载所有依赖。提问三自定义Spring Boot Starter作为依赖给其他项目引用应该用哪种打包方式3.1 结论必须使用普通JARmaven-jar-plugin而非Spring Boot Fat JAR3.2 原因分析打包方式能否作为依赖被引用原因普通JAR✅ 可以只包含项目class符合常规依赖库的规范Spring Boot Fat JAR❌ 不可以包含BOOT-INF/classes等特殊目录结构其他项目无法正常加载其中的class3.3 正确做法Step 1使用maven-jar-plugin打包xmlplugin groupIdorg.apache.maven.plugins/groupId artifactIdmaven-jar-plugin/artifactId version3.2.2/version /pluginStep 2不要使用spring-boot-maven-plugin的repackage目标如果父POM中已引入Spring Boot插件需要显式跳过xmlplugin groupIdorg.springframework.boot/groupId artifactIdspring-boot-maven-plugin/artifactId configuration skiptrue/skip !-- 跳过重打包 -- /configuration /pluginStep 3执行mvn clean package生成的JAR即可被其他项目通过Maven依赖引用。提问四Spring Boot Fat JAR启动时配置文件的加载顺序和优先级是什么4.1 核心规则Spring Boot加载配置文件的优先级从高到低如下优先级配置来源说明最高命令行参数--spring.config.location...或--server.port8081操作系统环境变量export SERVER_PORT8081JAR包外部的config/目录./config/application.yml4️⃣JAR包外部的根目录./application.yml5️⃣JAR包内部的config/目录classpath:/config/application.yml6️⃣最低JAR包内部的根目录classpath:/application.yml4.2 两条黄金法则先外部后内部JAR包外的配置优先于JAR包内的配置先config目录后根目录./config/优先于./4.3 Profile配置的优先级带profile的配置文件优先级高于不带profile的textapplication-dev.yml application.yml4.4 强制指定外部配置bashjava -jar myapp.jar --spring.config.locationfile:/opt/conf/application.yml或使用additional-location追加配置源bashjava -jar myapp.jar --spring.config.additional-locationfile:/opt/conf/提问五独立JAR包如何排除配置文件配置文件和依赖lib包放什么位置才能被访问到5.1 如何排除配置文件让JAR内部不含配置在maven-jar-plugin中添加excludesxmlplugin groupIdorg.apache.maven.plugins/groupId artifactIdmaven-jar-plugin/artifactId configuration excludes excludeapplication*.yml/exclude excludeapplication*.properties/exclude excludebootstrap*.yml/exclude excludelogback-*.xml/exclude /excludes /configuration /plugin5.2 配置文件和lib包的正确放置位置text部署目录/ ├── myapp.jar # 主JAR ├── lib/ # ✅ 所有依赖JAR通过Class-Path引用 │ ├── spring-core-xxx.jar │ └── ... ├── application.yml # ✅ 外部配置优先级高 └── config/ # ✅ 外部配置目录优先级最高 └── application.yml5.3 各路径的加载机制路径加载方式说明./lib/*.jar通过MANIFEST的Class-Path加载JVM启动时自动读取./application.ymlSpring Boot自动扫描优先级高于JAR内部配置./config/application.ymlSpring Boot自动扫描优先级最高classpath:/application.ymlJAR内部已被排除不存在5.4 重要提醒⚠️Java -jar 运行模式下无法通过-cp或-classpath参数指定依赖路径——这些参数会被JAR自身的MANIFEST覆盖。因此必须通过maven-jar-plugin在MANIFEST中预设Class-Path。总结对比表场景推荐打包方式配置外置依赖位置作为库/Starter被引用maven-jar-plugin普通JAR不适用由使用者管理独立应用部署依赖可升级maven-jar-plugindependency-plugin./config/或././lib/独立应用部署一键运行spring-boot-maven-pluginFat JAR./config/或./内置在JAR中需要解决依赖冲突maven-shade-plugin不推荐内置在JAR中如果觉得有用欢迎点赞、收藏、关注三连下期预告「自定义Spring Boot Starter 配置解密实战」——手把手带你写出一个生产级Starter。