你是不是也遇到过这种场景:项目在 IntelliJ IDEA 里跑得好好的,一说到打包 jar 包,瞬间变成大型事故现场。要么在右上角找半天没看到打包按钮,要么好不容易打出来个 jar,双击没反应,命令行执行报“no main manifest attribute”,再要么发给同事直接就说运行不起来。其实打包 jar 包这件事,本身不复杂,复杂的是它处在开发工具、构建工具、运行环境三者的交叉点上。任何一个环节的理解有偏差,都会以报错的形式回报你。
这篇文章我打算用我这些年实际踩坑攒下来的经验,把这个主题拆开揉碎讲清楚。不仅讲 IDEA 里怎么点,还会讲为什么要这么点,以及你打出来的 jar 到底能不能给别人用、能不能扔到服务器上跑。文章会覆盖三类读者:刚学会写 Java 的学生或初级开发、工作中需要交付 jar 包的普通程序员、以及负责框架维护或项目部署的进阶开发。如果你曾经在打包这事上浪费过一个下午,这篇文章就是为你写的。
1. 动手打包前,先想清楚这三件事
很多人在打包上翻车,不是操作不会,而是没想清楚自己到底要什么。我建议你先花三分钟回答三个问题,方向对了,后面所有操作都是水到渠成。
1.1 你要的是“能直接运行的 jar”,还是“给别人用的依赖包”
这是最容易被混淆的一点。同样是 jar 包,用途完全不同。
第一种是可执行 jar。你打包它的目的是为了部署,比如一个 Spring Boot 服务,最终在服务器上执行 java -jar xxx.jar 就能跑起来。这种 jar 需要包含启动主类信息,通常还需要把所有第三方依赖都打进去,业内叫“胖包”(fat jar)。
第二种是普通依赖包。你打包它是为了给其他项目引用,比如你们公司内部框架层代码编译成一个 jar,放到私服或者本地仓库,让其他模块通过 Maven 坐标依赖它。这种 jar 不需要包含第三方依赖,也不需要配置主类,只要把你自己写的 class 和资源文件打进去就行,体积一般很小。
这两种 jar 的打包方式完全不同。如果你拿打包依赖包的方式去打包一个 Spring Boot 项目,打出来的包放到服务器上执行,十有八九会报“找不到主类”或者“ClassNotFoundException”。反之,如果拿打包可执行 jar 的方式去处理一个纯工具类项目,打出来几百兆,别人引用起来又慢又难受。
1.2 你的项目是纯 IDEA 工程,还是 Maven / Gradle 工程
这三类工程的打包路径完全不一样。
纯 IDEA 工程指的是当初直接 File -> New -> Java Project 创建,没有加任何构建工具的项目。这种项目只能用 IDEA 自带的 Artifacts 功能来打包,过程比较手动,适合小型工具类项目。
Maven 工程是目前主流的工程形态,特征是项目根目录有 pom.xml。这种项目的打包依赖 Maven 的构建生命周期,能在 IDEA 的 Maven 工具窗口里一键触达,package 命令就能产出 jar 包。
Gradle 工程则是 build.gradle 文件,打包命令是 gradle jar 或 gradle bootJar。虽然 IDEA 对 Gradle 支持也不错,但这里我重点讲 Maven,因为从热搜词和实际使用比例来看,国内用了 Spring Boot 的公司,绝大多数是 Maven 工程。
先说一个判断方法:IDEA 界面右侧如果没有 Maven 工具窗口,且项目文件夹里找不到 pom.xml,那基本是纯 IDEA 工程。你要是不确定,先在项目根目录找一下有没有 pom.xml,这决定了你该走下面哪条路线。
1.3 你的项目有没有第三方依赖,依赖量有多大
这个问题的答案,直接决定你用哪种方式组织 jar 的依赖。
如果你的代码只用了 JDK 自带的类库,一个类都没从网上下载过,那打包非常轻松,直接 javac 编译后 jar 命令打包就行,或者用 IDEA 的 Artifacts 功能。
但只要引入了第三方库,比如用到了 Spring、MyBatis、某个数据库驱动、JSON 解析库,情况就变了。因为代码运行的时候,JVM 需要能找到这些类。第三方依赖没法凭空出现,你必须把它们以某种方式打进去。
处理第三方依赖有两种常见策略:一种是全部解压合并到最终 jar 里,做成一个“胖包”;另一种是把第三方依赖放在 jar 外部的 lib 目录,通过 Class-Path 环境变量引用。这两种方式在 IDEA 里对应两种不同的配置,后面我会详细说。
想清楚这三件事之后,你基本已经知道自己走哪条路了。下面我把两种主流方案分别展开,先用 IDEA 自带功能,再讲 Maven 方案。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 第一种做法:IDEA 自带 Artifacts 打包,图省事时的正确打开方式
如果你手里是个纯 IDEA 工程,或者临时快速打个小工具的 jar,用 IDEA 自带功能就够了。但这个东西坑比较多,如果不知道原理,很容易打出一个不能运行的残次品。
2.1 配置 Artifacts 时,最容易忽略的两个细节
先走一遍流程。打开项目,按 Ctrl + Shift + Alt + S 进入 Project Structure(也可以在菜单 File 里找到),选择 Artifacts,点加号,选择 JAR,然后选择 From modules with dependencies。
这时候会出现一个配置面板,关键点在这两个地方:
第一,Main Class 的选择。 这必须是你项目里有 main 方法的类。有人在这里随手选了个类,或者忘了选,结果打出来的 jar 没有入口点,点击运行毫无反应。对于 Spring Boot 项目,这里要选择那个带 @SpringBootApplication 注解的类。
第二,处理依赖的方式。 IDEA 会问你把依赖怎么放进 jar。它提供两个主要选项:
-
extract to the target JAR:把所有依赖的 class 文件全部解压,散开以后和你的代码合在一起打进同一个 jar。这种做法的好处是单文件自包含,java -jar 直接能跑;坏处是如果依赖里有同名文件(比如多个 jar 里都有 META-INF/services 下的 SPI 文件),后解压的会把前面的覆盖掉,容易引发莫名奇妙的问题。
-
copy to the output directory and link via manifest:保留所有第三方依赖 jar 的原本形态,把它们拷贝到最终输出目录下的一个 lib 文件夹里,然后在 MANIFEST.MF 里通过
Class-Path引用这些 jar。这种方式更干净,但你把 jar 发给别人或者部署到服务器时,必须把整个目录一并带上,jar 本身离开 lib 目录就运行不了。
这两个细节没搞对,是 IDEA 自带方式打包后运行失败的常见原因。尤其是选择打“胖包”的时候,你还要注意下面说的这个点。
2.2 为什么我劝你每次打包前先 Build 再 Clean
我用 IDEA 自带 Artifacts 打包时,踩过最邪门的一个坑是:代码明明改了,重新打出来的 jar 里还是旧 class。
原因是 IDEA 的 Jar 构建默认不会每次完整重新编译,它会把上一次编译输出的 class 直接拿来用。如果你项目里的代码是最近新改的,但没触发重新编译,或者上次编译失败后有残留,打包出来的就是一份过期产物。
这个问题的规避方式很简单:打包前手动执行一次 Build -> Build Project,确认编译通过,再去 Build Artifacts。如果有条件,把 Build -> Clean 和 Build Project 连着做一遍,也就是先清空 out 目录再重新编译。如果你发现自己改完代码,怎么打包运行结果都是老样子,九成是这个问题。
2.3 这种方案最大的隐患:依赖和资源文件
IDEA 自带 Artifacts 还有个明显的缺点:它默认处理资源文件的能力很弱。
如果你的项目依赖了某个第三方 jar,而这个 jar 内部又带有配置文件,通过 extract to the target JAR 方式解压合并时,这些配置有可能和你项目里的配置文件发生冲突,比如 Properties 文件、XML 文件、Spring 的 spring.factories 文件等。它们会在合并时互相覆盖,导致程序行为变得很诡异。
另外,如果你把文件放在项目根目录的 resources 文件夹下,IDEA 的 Artifacts 配置通常能把它复制进 jar,但你要是把配置文件放在了项目根目录等其他位置,它不会帮你自动包含,你得手动在 Output Layout 里添加这些文件。
所以我的结论是:IDEA 自带 Artifacts 只适合纯代码、逻辑简单、无复杂依赖的小工具项目。如果你的项目引用了 Spring、MyBatis 这类大型框架,我建议直接转向 Maven,因为依赖解析、资源复制、增量构建这些脏活,构建工具能做得比 IDE 更可靠。这也是为什么,现在绝大多数项目都要走构建工具。
3. 方案二:Maven 打包,多数项目更靠谱的归宿
如果你用的是 Maven 工程,那打包这件事本质就是执行 Maven 的命令。IDEA 只是提供一个图形化的按钮,真正干活的是 Maven 本身。理解了这一点,你就不会被 IDEA 菜单里各种奇怪的选项带偏。
3.1 先搞懂 package 和 install 的区别,别再糊涂地试
在 IDEA 右侧 Maven 工具窗口里,展开你的项目生命周期,能看到 clean、validate、compile、test、package、verify、install、deploy 这么一串。这是 Maven 的标准生命周期节点,每个节点会执行它之前的所有步骤。
package 命令会把编译好的代码打成一个 jar(或 war),放到每个模块下的 target 目录里。注意,它只是“打好了放在那里”,没有放进本地仓库。
install 命令在 package 的基础上,额外把这个 jar 安装到你本机 Maven 仓库(默认是 C:\Users\你的用户名\.m2\repository)。这一步特别重要,它解决的是多模块项目之间的依赖问题。
我举个实际场景:你有个项目拆成 framework 和 business 两个模块,business 依赖 framework。如果 framework 没有先 install 到本地仓库,business 执行 package 的时候会从远程仓库去找 framework 的坐标,本地没有就会报“Could not resolve dependencies”。这种情况下,很多人的第一反应是代码写错了,其实只是没把公共模块装到本地仓库。
所以多模块项目打启动模块的包之前,正确的顺序是:先对公共模块执行 install,再对启动模块执行 package。我见过太多人卡在这,一键 build 整个项目,报错了也不知道先去 install 依赖模块。
3.2 pom.xml 里最关键的三个配置,缺一个都会出幺蛾子
Maven 项目打包的最终效果,几乎完全由 pom.xml 控制。这里我挑三个平时最容易出问题的配置详细说明。
第一个,编译版本配置。 pom 里没有指定 maven-compiler-plugin 的 source 和 target,或者指定值和当前 JDK 不匹配,就会出现“maven 项目打包报错”,比如 invalid target release 或者一大堆语法错误。稳妥的做法是显式声明 Java 版本,我一般这样配:
xml复制<properties>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
1.8 对应 JDK 8,如果你的项目用的是 JDK 11 就写 11,JDK 17 就写 17。source 和 target 表示源码的语法版本和 class 文件的目标版本,它和当前 IDEA 用的 JDK 版本不一致时,IDEA 会提示你修改。
第二个,jar 插件的主类配置。 如果你打的是普通 jar,纯粹想通过 java -jar 运行,那你必须在 maven-jar-plugin 里指定主类,否则打出来的 jar 没有入口点:
xml复制<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.3.0</version>
<configuration>
<archive>
<manifest>
<mainClass>com.example.MainApplication</mainClass>
</manifest>
</archive>
</configuration>
</plugin>
不加这段,java -jar 运行时会报“no main manifest attribute”,这是搜索引擎里最常出现的问题之一。
第三个,Spring Boot 插件的 repackage 目标。 如果你用 Spring Boot,光有 maven-jar-plugin 不够,因为普通 jar 插件不会把第三方依赖合并进来。你需要 Spring Boot 官方的插件:
xml复制<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>2.7.0</version>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
这个插件的作用是在 package 阶段完成后,把原先那个“瘦” jar 重打包成一个嵌套了所有依赖的可执行 jar。没有这个插件,Spring Boot 项目打出来的 jar 缺依赖,部署到服务器上立刻崩。
3.3 定制化打包:assembly 插件解决“没有 parent 的烦恼”
除了 Spring Boot 的固定套路,很多普通 Java 项目也需要把依赖打成一个可运行 jar。这种场景用 maven-assembly-plugin 比较合适,它比 spring-boot 插件轻量,又比 maven-jar-plugin 多支持依赖合并。
典型配置长这样:
xml复制<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<version>3.6.0</version>
<configuration>
<archive>
<manifest>
<mainClass>com.example.Main</mainClass>
</manifest>
</archive>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
<executions>
<execution>
<id>make-assembly</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
执行 package 后,在 target 目录下会生成一个类似 xxx-jar-with-dependencies.jar 的文件,这就是把第三方依赖合并进去的可执行 jar。它很适合那种非 Spring Boot 的普通 Java 应用,比如一些用 Netty 写的小服务、内部工具、数据处理任务。
4. 打出来的 jar 双击没反应?先查 MANIFEST 和编译版本
不管用哪种方式打包,部署时最让人崩溃的事情永远是一样的:打出来的 jar 运行不起来。我见过太多人在这时候一头扎进代码里找问题,浪费几个小时,其实问题根本不在代码。
4.1 jar 包没你想的那么神秘,本质就是个 zip
分析运行失败的问题之前,先把 jar 包的底层结构搞明白。jar 包本质上就是一个 zip 压缩包,只不过里面多了一个 META-INF/MANIFEST.MF 文件。
这个 manifest 文件是 jar 包的控制信息文件,决定了 JVM 怎么看待这个 jar。可执行 jar 必须在这里声明 Main-Class: 你的主类全限定名。如果它缺失或者写错了,java -jar 就会找不到入口。
我在排查运行失败问题时,第一步永远是查看这个文件。Windows 下可以把 jar 后缀改成 zip,双击打开后进入 META-INF 目录,用记事本打开 MANIFEST.MF。Linux 服务器上更简单:
bash复制unzip -p your-app.jar META-INF/MANIFEST.MF
如果你手头没有 unzip,也可以用 JDK 自带的 jar 命令:
bash复制jar xf your-app.jar META-INF/MANIFEST.MF
cat META-INF/MANIFEST.MF
看到 Main-Class 这一行,基本就确认了入口点。如果文件里没有这行,那问题就清晰了:不是代码错了,是打包配置里主类没配。
4.2 排查顺序:先看依赖,再看主类,最后看版本
我在实际排查“java -jar 跑不起来”时,通常按以下顺序来:
第一步:看报错类型。 no main manifest attribute 是主类没配置;Exception in thread "main" java.lang.NoClassDefFoundError 是某个依赖类没找到;UnsupportedClassVersionError 是 class 编译版本高于当前 JDK 版本。
第二步:查依赖。 如果你是普通 jar 打包方案,第三方依赖通常需要放在 jar 外的 lib 目录,且 MANIFEST.MF 里的 Class-Path 必须正确指向这些 jar。前面提到的 IDEA 的 “copy to the output directory and link via manifest” 方案,就属于这种。你拷贝整个目录的时候,jar 和 lib 的目录层级不能乱,否则 Class-Path 就失效了。
第三步:查编译版本。 这是最容易忽略的服务器问题。你在本地用 JDK 17 编译打包,到服务器上跑,服务器上可能只有 JDK 8。JDK 是向下兼容的,也就是 JDK 8 跑不了 JDK 17 编译出来的 class。解决办法有两个:一是让服务器装和开发环境一致甚至更高的 JDK;二是在 pom 里把编译版本降到服务器支持的版本。检查 class 文件版本可以用这条命令:
bash复制javap -verbose 你的类名.class | grep major
输出里的 major version 对应关系大致是这样:52 是 Java 8,55 是 Java 11,61 是 Java 17。如果服务器 JDK 是 8,而 class 版本是 61,那不管你怎么调代码都没用,只能在编译侧降级。
4.3 Bootdo、RuoYi 这类框架二次打包时的特殊点
很多公司用 Bootdo、RuoYi 这类快速开发平台,它们都是多模块 Maven 结构。这种项目框架代码和业务代码分离,第一次接手的人去打包,经常会遇到一个现象:单独打包业务模块,报“找不到依赖”。
实际上,这类平台在修改任何公共模块代码后,都必须先把公共模块 install 到本地仓库。网上比较常见的操作是:项目根目录打开 Maven 面板,先在 common、framework、system 这些模块执行 install,再切到 admin(或启动类所在模块)执行 package。
如果你已经把框架层代码放到了公司私有仓库,其他模块通过 Maven 坐标依赖,那流程变成了:框架层模块发布到私库 -> 业务模块从私库拉取依赖 -> 打包。这里要特别强调,私库地址必须在 settings.xml 里配置好,否则 Maven 去中央仓库找不到内部包,又会报依赖解析失败。
5. 依赖打进去了还是跑不起来?资源文件丢失和配置外置
解决了“依赖没打进去”问题之后,你以为万事大吉,结果一运行,程序能启动,但各种资源文件读取失败、数据库连接不上、中文显示乱码。这些问题的根源不在依赖,而在资源文件的处理上。
5.1 为什么 resources 下面的配置文件会“消失”
Maven 编译时,默认会把 src/main/resources 目录下的文件复制到 target/classes。如果你的项目结构标准,配置文件放对了位置,打出来的 jar 里应该能正常看到这些文件。
但有一种情况很坑:你在 pom.xml 里配置了 resources 节点,用来额外指定资源目录,比如:
xml复制<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
</resource>
</resources>
开启 filtering 后,Maven 会把资源文件里的 ${变量} 做属性替换。如果某个变量在 pom 或 properties 里没有定义,替换后的文件会被破坏,比如一个正常的 Shell 脚本里出现 ${JAVA_HOME},Maven 会把它替换成空字符串。这样打出来的 jar 能启动,但里面的脚本文件全是坏的。
另外,如果项目用 Spring Boot 的 spring-boot-maven-plugin 打了可执行 jar,嵌套结构比普通 jar 多一层。你不能再直接用 unzip 去看 classes 目录里的 configuration 文件,得用 Spring Boot 特有的 jar --extract 或者直接跑起来之后看日志。这个结构差异,是很多人找不到配置文件的原因。
5.2 把 application.yml 外置,改配置不用重新打包
部署 Spring Boot 项目时,最烦的事情就是每次改个数据库密码都要重新打一次 jar。其实 Spring Boot 支持外部配置文件覆盖 jar 内配置,原理是它的配置加载顺序里,外部文件优先于 jar 包内文件。
你可以在 jar 包同级目录放一个 application.yml,甚至建一个 config 目录把配置文件放进去。启动时 Spring Boot 的加载顺序大致是:本地 config 目录里的配置 > 当前目录里的配置 > jar 包内的配置。
还有一个更可控的启动方式,用 spring.config.location 指定配置绝对路径:
bash复制java -jar your-app.jar --spring.config.location=/etc/app/application.yml
这种方式生产环境最常用。打包时你可以选择把 jar 里的配置文件排除掉,避免内部的默认值把外部配置覆盖掉。至于怎么排除,我不太建议用复杂的脚本去改 jar,更稳妥的办法是:pom 里把配置文件从最终 jar 中排除的配置我一般不用,直接告诉运维同学不要动 jar 内的内容,外部放一份完整配置文件,按顺序他们自己就能理解。
5.3 中文字符乱码和文件编码问题
另一个高频坑是中文乱码。代码在 IDEA 里显示正常,打成 jar 放到服务器上跑,日志里的中文全变成乱码。
这个问题的根源大概率是编译时没指定统一的字符编码。前面 pom 里 project.build.sourceEncoding 设置成 UTF-8 能解决大部分问题。但如果你还没设置,IDEA 的编译默认可能用的是系统编码,Windows 下是 GBK,Linux 下是 UTF-8,两边交叉就会乱。
我的建议是在 pom 的 properties 里加上:
xml复制<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
如果还乱码,那就是运行时 JVM 编码问题。启动 jar 时加上参数:
bash复制java -Dfile.encoding=UTF-8 -jar your-app.jar
这几步下来,绝大多数中文乱码问题都能解决。
6. 一次真实的排查全过程:从“打包报错”到“服务器正常运行”
理论知识说完了,这一节我用一个真实场景,把整个排查过程完整走一遍。这个场景我在工作里遇到过不止一次,几乎就是热搜词里“IntelliJ + Maven 项目打包报错”的现实版本。
6.1 接到的报错信息长什么样
当时的情况是:我接手同事的半成品项目,在 IDEA 里执行 mvn package,控制台刷出一堆日志后挂掉,核心报错长这样:
code复制[ERROR] Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.0:compile
[ERROR] /path/to/SomeClass.java:[28,20] cannot find symbol
刚开始我以为只是代码语法问题,打开错误指向的类检查代码,发现根本没毛病。再仔细看报错,这句 “cannot find symbol” 其实指的是某一个自定义工具类。类在别的模块里,而那个模块没有安装到本地仓库。
6.2 完整的排查链路
第一步:定位第一行报错,而不是只看最后一行。 Maven 报错信息里,最有价值的往往是第一个 [ERROR] 出现的位置。很多人习惯截图最后有 [ERROR] 的大段红字,其实那只是 Maven 的版本号和插件调用栈,根本的失败原因得往上翻。
第二步:识别错误类别。 我根据 cannot find symbol 判断是依赖问题,而不是代码语法问题。在 IDEA 里按 Ctrl 点击报错提示的类,发现这个类来自另一个模块。于是我先确认这个模块是否 install 了。执行:
bash复制mvn install -pl framework -DskipTests
其中 -pl 指定要构建的模块,-DskipTests 跳过测试。执行完,再回到启动模块执行 mvn package,这次编译通过了。
第三步:检查 target 目录下 jar 包大小。 编译通过之后,我发现 xxx.jar 只有 30KB。一个用了 Spring Boot 和 MyBatis 的项目,依赖加起来起码几十兆,jar 只有 30KB,说明这不是一个可执行胖包。检查 pom,发现 spring-boot-maven-plugin 的配置被注释掉了。我把插件配置恢复,重新执行 mvn package,jar 变成了 55MB 左右,这才像样。
第四步:本地验证 jar 可运行性。 在 target 目录里执行:
bash复制java -jar xxx.jar
程序成功启动,说明主类和依赖都正常。这一步很关键,在本地把运行问题解决掉,再上服务器,能省下大量和服务器环境纠缠的时间。
第五步:上服务器部署。 把 jar 拷到服务器,启动之前先检查服务器 JDK 版本:
bash复制java -version
确认是 JDK 8,本地打包也是 JDK 8,版本一致。之后用 nohup 方式后台启动:
bash复制nohup java -jar /opt/app/xxx.jar --spring.profiles.active=prod \
--spring.config.location=/opt/app/application-prod.yml > /opt/app/log.out 2>&1 &
注意把日志重定向到文件,这样即使终端断开,程序也能继续跑。启动后看一眼日志有没有异常,再 curl 一下健康检查接口,确认服务已经注册到注册中心。
6.3 事后的通用定位清单
这次排查之后,我把这套思路沉淀成了一张清单,之后每次遇到打包部署问题,都是按这个顺序过:
| 现象 | 优先检查项 | 常见解法 |
|---|---|---|
| package 阶段编译报错 | 本地仓库依赖是否完整 | 先 install 依赖模块,再 package |
| jar 包很小(几十 KB) | 是否配置了打包插件 | 检查 spring-boot-maven-plugin 或 assembly 插件 |
| java -jar 报 no main manifest | MANIFEST.MF 主类配置 | 检查 maven-jar-plugin 的 mainClass |
| java -jar 报 ClassNotFoundException | 依赖是否打进 jar | 使用胖包插件或 lib 目录加 Class-Path |
| 服务器报 UnsupportedClassVersionError | class 编译版本 | 对比开发 JDK 和服务器 JDK 版本 |
| 启动后连不上数据库 | 配置文件是否外置 | 检查 config 目录或 spring.config.location |
| 日志中文乱码 | 编码设置 | 设置 UTF-8 编码并检查启动参数 |
这张表不是教条,它是我把常见问题按照“编译期 -> 打包期 -> 启动期 -> 运行期”阶段划分出来的。每个阶段的问题都有各自的典型现象,先归类再动手,效率会高很多。
回到最初的那个问题:打包 jar 包到底难不难?说实话,点按钮的操作五分钟就能学会,真正常出问题的是对构建流程底层的理解。项目用了什么构建工具、依赖怎么处理、主类有没有配置、JDK 版本对不对、配置文件放哪里——这几件事想清楚了,打包就是个机械操作。反过来,你就算把 IDEA 的菜单栏背下来,不搞懂机制,换个项目、换个框架照样会栽。希望这篇讲清楚原理的文章,能让你下次打包的时候,能少走一些我当年走过的弯路。
