[Step4]启动器配置——开启Idea debug
# 一、说明
前面几篇已经把本机 Debug 所需的基础环境准备好了,包括:
version文件ambari.propertieslog4j.properties- 本地运行目录
local-runtime - 本地配置目录
local-dev
做到这一步,其实只是把运行条件补齐。
如果 IDEA 的启动器没有配置好,后面依然会遇到这些问题:
- 代码可以编译,但 IDEA 里启动不起来
- 本地改过的配置没有真正生效
- 日志文件已经准备好,但控制台没有按预期输出
- 断点已经下好了,程序却在进入业务逻辑之前先报错
所以这一篇单独把 Run Configuration 这一层补完整。
这一层接通之后,Ambari Server 才算真正进入 可以在 IDEA 中本机启动、直接打断点、直接观察日志 的状态。
提示
这一篇解决的是启动入口问题。
前面的内容是在准备环境,这一篇是在把环境真正接进 IDEA。
# 1. 这一篇到底要解决什么
这一篇并不是单纯“建一个启动项”,而是把本机 Debug 需要的几个关键入口一次性接通:
# 1.1 启动入口要固定到源码主类
Ambari Server 本地启动时,入口类必须明确指向:
org.apache.ambari.server.controller.AmbariServer
如果入口类不对,后面的配置再完整也没有意义。
# 1.2 本地配置目录要强制切换
本机 Debug 不是走系统安装目录,而是走前面已经准备好的 local-dev。
所以启动器里必须显式指定:
AMBARI_CONF_DIR=$PROJECT_DIR$/ambari-server/conf/unix/local-dev
否则程序很容易去读取系统已有配置,或者读到不符合当前源码状态的旧配置。
# 1.3 日志配置要真正参与类加载
前一篇已经把 log4j.properties 改造成了本地开发版本,但仅仅把文件放在 local-dev 里还不够。
还需要把这个目录加入运行 classpath,这样 log4j.properties 才能被类加载器找到。
# 1.4 JDK 17 兼容参数要一次补齐
如果当前本地使用的是 JDK 17,那么 --add-opens 不能少。
这不是“有空再加”,而是启动器里必须先配进去的内容。
否则很多依赖在反射访问阶段就会直接抛异常。
注意
本机 Debug 最常见的问题,通常都不是源码逻辑本身,而是启动器配置不完整。
尤其是 AMBARI_CONF_DIR、classpath、--add-opens、provided scope` 这几个点,少任何一个都可能导致启动异常。
# 2. 两种配置方式怎么理解
Run Configuration 这里有两种写法,二选一即可。
# 2.1 方案一:通过 IDEA 界面手动创建
这种方式更适合第一次搭环境。 因为每一个配置项都能在界面里看到,边配边核对,出问题时也更容易顺着界面往回检查。
# 2.2 方案二:直接写入 XML 配置
这种方式更适合已经跑通过一遍的人。
尤其是团队协作时,直接把 .idea/runConfigurations/*.xml 整理好,别人拉下代码后就能直接用,省得再手动点一遍。
点击查看
两种方式本质上生成的是同一份启动器配置。 区别只是:一个通过 IDEA 页面填进去,一个通过 XML 直接落到工程目录里。
# 二、方案一:通过 IDEA 界面创建启动器
这一部分建议第一次就按界面方式走一遍。 这样后面就算 XML 丢了,自己也能重新配回来。
# 1. 进入 Run Configuration 编辑界面
先打开 Run Configuration 的编辑入口。
# 1.1 打开入口
菜单栏进入:
Run → Edit Configurations…
也可以通过右上角运行配置下拉框进入:
Edit Configurations…

# 1.2 这里的作用是什么
这里是 IDEA 统一管理启动器的位置。 后面不管是 Java Application、JUnit、Remote JVM Debug,还是其他调试配置,都会在这里维护。
# 2. 新建 Application 配置
进入编辑界面后,点击左上角 +,选择 Application。

# 2.1 为什么要选 Application
这里必须选择 Application。
因为当前是直接从 Java 主类把 Ambari Server 拉起来,不是跑测试,也不是做远程附加。
# 2.2 如果选错会怎么样
如果误选成其他类型,最常见的问题就是:
- 主类入口无法正常配置
- classpath 组织方式不对
- 启动参数字段不完整
- 后面即使补环境变量,也无法按 Application 的方式运行
# 3. 填写基础信息
创建完成后,先把下面几个核心字段补齐:
| 字段 | 值 |
|---|---|
| Name | AmbariServer Debug |
| Module | ambari-server |
| Main class | org.apache.ambari.server.controller.AmbariServer |
| Working directory | $PROJECT_DIR$/ambari-server |

# 3.1 Main class
Main class 右侧点击 ...,搜索 AmbariServer,直接选择:
org.apache.ambari.server.controller.AmbariServer
# 3.1.1 为什么必须是这个类
这是 Ambari Server 本机启动时的主入口。 如果这里配成别的类,表面上看像是“有 main 方法、也能启动”,但真正走的并不是当前要调试的启动链路。
# 3.1.2 配错后的常见现象
- 程序能起,但不是预期入口
- 断点打下去不生效
- 配置读取行为和预期不一致
- 启动链路完全偏掉
# 3.2 Module
模块这里要明确选择 ambari-server。
不要选顶层工程,也不要选其他子模块。
# 3.2.1 为什么 Module 不能随便选
因为 IDEA 在运行 Application 时,会基于 Module 去组织 classpath。 如果模块选错,常见表现通常不是直接提示“模块错误”,而是下面这种更隐蔽的问题:
- 编译没问题,但运行时找不到某些类
- Main Class 能找到,但依赖链路不完整
- 运行到初始化阶段才报
NoClassDefFoundError
# 3.3 Working directory
这里建议固定成:
$PROJECT_DIR$/ambari-server
# 3.3.1 为什么不要写成仓库根目录
Working Directory 会影响一部分相对路径的解析结果。 如果这里偏了,某些资源定位、脚本调用、运行时文件读取就可能表现异常。
提示
本机 Debug 场景里,Working directory 看起来不起眼,但经常是导致“配置都对了,运行还是不对”的隐藏因素。
# 4. 配置 VM options
基础信息填完之后,下一步就是补 JVM 启动参数。
# 4.1 打开 VM options 输入框
点击 Modify options,勾选 Add VM options。

然后填入下面这组参数:
-Xms512m -Xmx2048m -ea --add-opens java.base/java.lang=ALL-UNNAMED --add-opens java.base/java.lang.reflect=ALL-UNNAMED --add-opens java.base/java.lang.invoke=ALL-UNNAMED
# 4.2 参数说明
| 参数 | 作用 |
|---|---|
-Xms512m | JVM 初始堆内存 |
-Xmx2048m | JVM 最大堆内存 |
-ea | 开启断言 |
--add-opens java.base/java.lang=ALL-UNNAMED | 放开 java.lang 反射访问 |
--add-opens java.base/java.lang.reflect=ALL-UNNAMED | 放开 java.lang.reflect 反射访问 |
--add-opens java.base/java.lang.invoke=ALL-UNNAMED | 放开 java.lang.invoke 反射访问 |
# 4.3 JDK 17 下为什么必须加 add-opens
如果当前本地使用的是 JDK 17,这三项 --add-opens 不能少。
因为 JDK 17 对模块访问限制更严格,Ambari Server 以及依赖链路里的部分反射访问,在开发态非常容易碰到访问受限问题。
最常见的报错就是:
InaccessibleObjectException
# 4.3.1 为什么这种错误特别容易误导人
因为它不一定会在一启动就抛出来。 它也可能在下面这些阶段才出现:
- 某个初始化组件开始反射处理时
- 某个框架桥接逻辑触发时
- 某个依赖在运行时访问内部包时
注意
这三个 --add-opens 建议一次性完整保留,不要删一条试一条。
本机 Debug 不是做最小参数压缩,能稳定拉起来才是重点。
# 5. 配置环境变量
除了 VM 参数,环境变量也是这份启动器里必须显式补进去的内容。
# 5.1 添加 AMBARI_CONF_DIR
点击 Modify options,勾选 Environment variables。
然后点击输入框末尾的 ... 图标,新增下面这一项:
| Name | Value |
|---|---|
AMBARI_CONF_DIR | $PROJECT_DIR$/ambari-server/conf/unix/local-dev |

也可以直接使用等号形式填写:

# 5.2 这个变量到底在解决什么问题
AMBARI_CONF_DIR 的作用,就是告诉程序:
当前启动时,应该去哪里找 Ambari 的配置文件
在这套本机 Debug 方案里,它必须明确指向:
$PROJECT_DIR$/ambari-server/conf/unix/local-dev
# 5.2.1 为什么必须切到 local-dev
因为前面几篇做过的本地化改造,基本都落在这里。 包括:
- 本地版
ambari.properties - 本地版
log4j.properties - 调试阶段额外覆盖的配置项
# 5.2.2 如果没配会出现什么现象
如果这里没配,或者路径配错了,就很容易出现这种现象:
- 你明明改过配置
- 文件也明明确认存在
- 结果启动后完全不像你本地那套配置
这通常不是文件写错了,而是程序根本没去读这套目录。
警告
本机 Debug 时,如果出现“配置完全不像是我改过的那份”,优先检查 AMBARI_CONF_DIR,不要先怀疑源码。
# 6. 追加 classpath,让 log4j 真正生效
这一项经常和上面的环境变量混在一起理解,但它们解决的并不是同一件事。
# 6.1 添加目录到 classpath
点击 Modify options,勾选 Modify classpath。 然后在 Add 下选择 Add directory,填入:
$PROJECT_DIR$/ambari-server/conf/unix/local-dev

# 6.2 为什么已经配了 AMBARI_CONF_DIR,还要再加 classpath
这是两个不同层面的入口:
| 配置项 | 作用 |
|---|---|
AMBARI_CONF_DIR | 告诉 Ambari 去哪里找配置 |
Modify classpath | 让类加载器能找到 log4j.properties 等资源 |
也就是说,AMBARI_CONF_DIR 负责程序级配置目录入口,
classpath 追加负责把目录真正挂到 Java 运行时资源加载链路上。
# 6.3 这一步为什么对控制台日志特别关键
前一篇里已经把开发态日志改造成了:
- 文件输出
- 控制台输出双通道
但那份 log4j.properties 要想真正生效,还得让类加载器能看到它。
而这一步,就是把 local-dev 接进类加载链路的关键动作。
提示
如果 IDEA 控制台中的日志很少、格式不对、没有行号,或者不像前一篇配置的效果,优先检查这里。
# 7. 勾选 provided 依赖
接下来还有一项很容易漏掉,但漏掉之后最容易把排查方向带偏。
# 7.1 开启 provided 依赖参与运行
点击 Modify options,勾选:
Include dependencies with 'Provided' scope

# 7.2 为什么 provided scope 也要参与运行
在安装包运行场景下,有些依赖是由外部环境、容器或者安装路径提供的。 但本机通过 IDEA 直接把主类拉起来时,运行环境和安装态并不是同一回事。
如果 provided scope 没有被带进来,启动时就很容易在初始化阶段出现这些错误:
ClassNotFoundExceptionNoClassDefFoundError
# 7.2.1 为什么这类问题特别像“依赖坏了”
因为表面上看起来往往是:
- 代码能编译
- 模块也导入了
- Main Class 也能找到
但一点击 Debug,程序还没真正进入业务逻辑,就先在依赖链路上缺类了。
注意
如果 Ambari Server 本机启动时报缺类,不要第一时间怀疑源码损坏或本地仓库坏了,先确认 provided scope 是否已经带上。
# 8. 保存并启动
前面这些配置项都补齐之后,就可以把启动器真正保存下来并开始调试。
# 8.1 保存配置
点击 OK 保存配置。
# 8.2 使用 Debug 模式启动
回到 IDEA 右上角,选择:
AmbariServer Debug
接着点击 Debug 图标(虫子) 启动。

# 8.3 第一次启动时建议先观察什么
第一次更建议先确认启动链路是否通畅,而不是急着下很多业务断点。 启动后优先看下面这些行为是不是正常:
- 控制台是否开始持续输出日志
- 输出格式是否符合本地
log4j.properties - 是否正确读取了
local-dev - 是否连上了远程数据库
- 是否出现反射访问异常
- 是否出现缺类问题
# 8.3.1 为什么先跑通再打断点
这一轮先确认的是“启动器能不能把服务稳定拉起来”。 等确认这条链路通了,再去下断点看初始化细节,效率会高很多。
提示
第一次更建议先跑通一遍,再开始断点。 否则一边配启动器一边打断点,问题会混在一起,排查很容易乱。
# 三、方案二:通过 XML 直接落库启动器配置
如果不想手动点界面,也可以直接把 Run Configuration 写成 XML 文件。 这种方式更适合已经验证过启动链路、希望把结果固化下来的人。
# 1. 配置文件位置
把下面这个文件放到:
.idea/runConfigurations/AmbariServer_Debug.xml
对应位置如下:

# 1.1 为什么文件路径要固定在这里
因为 IDEA 会从 .idea/runConfigurations/ 下读取项目级运行配置。
把 XML 放到这个目录里,工程重新打开后,启动器就能直接识别出来。
# 2. XML 配置内容
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="AmbariServer Debug" type="Application" factoryName="Application">
<option name="MAIN_CLASS_NAME" value="org.apache.ambari.server.controller.AmbariServer"/>
<module name="ambari-server"/>
<option name="VM_PARAMETERS"
value="-Xms512m -Xmx2048m -ea --add-opens java.base/java.lang=ALL-UNNAMED --add-opens java.base/java.lang.reflect=ALL-UNNAMED --add-opens java.base/java.lang.invoke=ALL-UNNAMED"/>
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/ambari-server"/>
<option name="INCLUDE_PROVIDED_SCOPE" value="true"/>
<method v="2">
<option name="Make" enabled="true"/>
</method>
<envs>
<env name="AMBARI_CONF_DIR" value="$PROJECT_DIR$/ambari-server/conf/unix/local-dev"/>
</envs>
<classpathModifications>
<entry path="$PROJECT_DIR$/ambari-server/conf/unix/local-dev"/>
</classpathModifications>
</configuration>
</component>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 2.1 这份 XML 对应了哪些界面配置
这份 XML 本质上就是把方案一中的界面配置结果固化下来,包括:
- Main Class
- Module
- VM 参数
- Working Directory
- provided scope
- 环境变量
- classpath 追加目录
# 2.2 为什么说它和方案一本质一致
因为它们最终生成的是同一份 Run Configuration。 区别只是:
- 方案一:通过界面逐项填写
- 方案二:直接把最终结果写入工程目录