用 Gradle 配置 Flink 从开发到打包的一条龙实践
一、环境要求与项目初始化
- Gradle:7.x
- Java:11(支持 8,但已不推荐)
提示:若你使用 Gradle Wrapper,命令均可替换为
./gradlew ...
,避免本机 Gradle 版本不一致。
二、IDE 导入与本地运行
-
IntelliJ IDEA:原生 Gradle 插件即可。
- 运行配置里勾选 Include dependencies with “Provided” scope(旧版没有该选项时,可写一个测试用例调用
main()
代跑)。 - JVM 堆内存:
Help -> Edit Custom VM Options
,增加如-Xmx800m
。
- 运行配置里勾选 Include dependencies with “Provided” scope(旧版没有该选项时,可写一个测试用例调用
-
Eclipse:使用 Eclipse Buildship 插件(导入向导最后一步确保 Gradle 版本 ≥ 3.0,Shadow 插件需要)。
三、项目结构与主类配置
-
默认示例主类通常叫
StreamingJob
(可能因模板而异)。 -
若主类不同,建议在
build.gradle
中设置:application {mainClass = 'org.example.MyJob' // Gradle 7 推荐写法 }
或在
shadowJar
的 Manifest 中指定主类(见第六节)。
这样打包后的 JAR 直接被 Flink 识别,无需每次提交都
-c org.example.MyJob
。
四、依赖管理:provided
与 compile
的边界
核心原则:
- Flink 核心/运行时(例如
flink-clients
、flink-table-runtime
、flink-table-planner-loader
)由集群提供 → 在工程中标记为 provided/compileOnly,不要打进 JAR。 - 你必须随作业分发的依赖(连接器、格式库、业务 SDK)→ 设为 compile/runtime,并通过 Shadow 打包进 fat/uber JAR。
示例(build.gradle
):
plugins {id 'java'id 'application'id 'com.github.johnrengelman.shadow' version '8.1.1'
}ext {flinkVersion = '2.1.0'
}repositories { mavenCentral() }dependencies {// 1) API(按需)implementation "org.apache.flink:flink-streaming-java:${flinkVersion}"implementation "org.apache.flink:flink-table-api-java:${flinkVersion}"implementation "org.apache.flink:flink-table-api-java-bridge:${flinkVersion}"// 2) 连接器/格式(打进 fat JAR)implementation "org.apache.flink:flink-connector-kafka:${flinkVersion}"implementation "org.apache.flink:flink-json:${flinkVersion}"// 3) 集群提供的运行时(不要打包)compileOnly "org.apache.flink:flink-clients:${flinkVersion}"compileOnly "org.apache.flink:flink-table-runtime:${flinkVersion}"compileOnly "org.apache.flink:flink-table-planner-loader:${flinkVersion}"// 4) 测试testImplementation "org.apache.flink:flink-test-utils-junit:${flinkVersion}"testImplementation "org.junit.jupiter:junit-jupiter:5.10.2"
}application {mainClass = 'org.example.MyJob'
}tasks.withType(Test).configureEach {useJUnitPlatform()
}
五、添加依赖的常见场景
以 Kafka Connector 为例(shadow 专用的配置法在很多模板中叫 flinkShadowJar
;若无该自定义配置,implementation
即可):
dependencies {// 如果模板定义了 'flinkShadowJar' 以便区分要打进 fat JAR 的依赖flinkShadowJar "org.apache.flink:flink-connector-kafka:${flinkVersion}"// 若没有该自定义配置,使用 implementation 也能被 Shadow 打入// implementation "org.apache.flink:flink-connector-kafka:${flinkVersion}"
}
关键不是名字,而是这些依赖最终会进入 Shadow 产物;而 Flink 核心运行时保持
compileOnly/provided
。
六、打包策略:普通分发 vs fat/uber JAR
命令一览:
-
本地快速打包 fat JAR(常用):
gradle clean shadowJar
产物:
build/libs/<project>-<version>-all.jar
-
安装可分发目录(不含第三方 fat 合并):
gradle clean installDist
适合“只依赖 Flink 发行版内置组件”的简单作业(例如 filesystem + JSON)。
-
安装 fat 分发目录(单 JAR 带齐第三方依赖):
gradle clean installShadowDist
产物在:
build/install/<project>/lib/
(包含单一 fat JAR)。
Shadow 细节(可选优化):
tasks.shadowJar {archiveClassifier.set('all')mergeServiceFiles()exclude 'META-INF/*.SF', 'META-INF/*.DSA', 'META-INF/*.RSA' // 避免签名冲突manifest {attributes 'Main-Class': 'org.example.MyJob' // 双保险:Manifest 写主类}
}
建议:生产环境用 fat/uber JAR 更省心:一次打包,处处可跑;但务必别把 Flink 运行时也打进去。
七、提交运行与命令示例
bin/flink run -c org.example.MyJob build/libs/my-job-1.0.0-all.jar
# 若 Manifest 已写 Main-Class,可省略 -c:
# bin/flink run build/libs/my-job-1.0.0-all.jar
亦可在 Kubernetes Application/Session 模式下提交,上线前先在测试集群验证。
八、常见问题与排查清单
(1)JAR 过大或类冲突
- 症状:依赖冲突、
NoSuchMethodError
、LinkageError
。 - 原因:把
flink-clients/table-runtime/planner-loader
这类运行时打进了 fat JAR。 - 解决:改为
compileOnly
/provided
,重新打包;核对依赖树(gradle dependencies
)。
(2)IDE 能跑,集群报错
- 原因:集群的 Flink 版本与本地依赖不匹配,或缺少对应运行时。
- 解决:统一版本;确保运行时由集群提供,应用仅携带连接器与三方库。
(3)主类找不到
- 原因:打包未写
Main-Class
,或改了主类却没同步到配置。 - 解决:
application { mainClass = ... }
或在shadowJar.manifest
写入。
(4)内存不足
- 现象:IDE 或本地运行时 OOM。
- 处理:增加 JVM 堆(
-Xmx800m
起步),或在运行配置调大。
(5)Kafka/格式类找不到
- 原因:连接器/格式库没有被 Shadow 打进产物。
- 解决:确认依赖在
implementation
或模板的flinkShadowJar
;重新打包shadowJar
。
九、实践建议与下一步
(1)以 Kafka → 清洗 → Sink 的最小链路为骨架,先在本地跑通。
(2)用 shadowJar 生成 fat JAR,在测试集群验证端到端。
(3)在 CI/CD 中固化:Gradle Wrapper + 版本锁定 + 产物归档 + 自动提交。
(4)连接器与 Flink 版本强一致;显式设置有状态算子的 UID(与部署相关,但同样建议固定)。
把 依赖作用域 划清、把 Shadow 打包 配好、把 主类 写明白,你的 Flink + Gradle 项目就能稳定地在“开发—构建—部署”全链路运行。祝你第一条 Flink 作业流水线顺利上线!