用 Maven 配置 Flink 从初始化到可部署的完整实践

一、环境与初始化

要求:

  • Maven ≥ 3.8.6
  • Java 11

初始化方式:

bash 复制代码
# 方式一:Archetype(交互式填写 groupId/artifactId/package)
mvn archetype:generate \
  -DarchetypeGroupId=org.apache.flink \
  -DarchetypeArtifactId=flink-quickstart-java \
  -DarchetypeVersion=2.1.0

# 方式二:一键脚本
curl https://flink.apache.org/q/quickstart.sh | bash -s 2.1.0

二、将项目导入 IDE 并能"跑起来"

  • IntelliJ IDEA :原生支持 Maven 项目;在 Run/Debug Configurations 勾选
    Include dependencies with "Provided" scope (旧版无此选项时,可写一个测试用例调用 main() 作为变通)。
  • Eclipse :安装 m2e 插件导入 Maven 项目。

JVM 堆内存:默认堆可能偏小。

  • Eclipse:Run Configurations -> Arguments -> VM Arguments 添加:-Xmx800m
  • IntelliJ:Help -> Edit Custom VM Options 调整。

三、依赖管理的"黄金法则"

一个 Flink 作业通常需要三类依赖:

(1)Flink API (DataStream、Table/SQL 等)

(2)连接器/格式 (Kafka、Filesystem、JSON/Avro 等)

(3)测试工具(例如 JUnit 与 Flink test utils)

(一)常见 API 依赖选择

  • DataStream:flink-streaming-java
  • Table(Java):flink-table-api-java
  • Table + DataStream(Java 桥):flink-table-api-java-bridge
    (Scala 版本请使用 _2.12 对应构件)

(二)"provided" 与 "compile" 怎么选?

  • Flink 核心/运行时模块 (如 flink-clients、flink-table-runtime、flink-table-planner-loader)
    在集群 中已有,应设为 provided (只编译,不打进 JAR)------避免 JAR 过大 和 版本冲突。
  • 必须随 JAR 分发的依赖 (连接器、格式库、三方 SDK)
    设为 compile ,并用 Shade 打进 uber/fat JAR。

一句话记忆:能让集群提供的就 provided;必须带去运行现场的就 compile + shade。

四、典型 pom.xml 片段

xml 复制代码
<properties>
  <maven.compiler.source>11</maven.compiler.source>
  <maven.compiler.target>11</maven.compiler.target>
  <flink.version>2.1.0</flink.version>
</properties>

<dependencies>
  <!-- (一)APIs(按需添加) -->
  <dependency>
    <groupId>org.apache.flink</groupId>
    <artifactId>flink-streaming-java</artifactId>
    <version>${flink.version}</version>
  </dependency>
  <dependency>
    <groupId>org.apache.flink</groupId>
    <artifactId>flink-table-api-java</artifactId>
    <version>${flink.version}</version>
  </dependency>
  <dependency>
    <groupId>org.apache.flink</groupId>
    <artifactId>flink-table-api-java-bridge</artifactId>
    <version>${flink.version}</version>
  </dependency>

  <!-- (二)连接器/格式(随 JAR 分发,compile) -->
  <dependency>
    <groupId>org.apache.flink</groupId>
    <artifactId>flink-connector-kafka</artifactId>
    <version>${flink.version}</version>
  </dependency>

  <!-- (三)本地运行 main 需要,但集群会提供:设为 provided -->
  <dependency>
    <groupId>org.apache.flink</groupId>
    <artifactId>flink-clients</artifactId>
    <version>${flink.version}</version>
    <scope>provided</scope>
  </dependency>
  <dependency>
    <groupId>org.apache.flink</groupId>
    <artifactId>flink-table-runtime</artifactId>
    <version>${flink.version}</version>
    <scope>provided</scope>
  </dependency>
  <dependency>
    <groupId>org.apache.flink</groupId>
    <artifactId>flink-table-planner-loader</artifactId>
    <version>${flink.version}</version>
    <scope>provided</scope>
  </dependency>

  <!-- (四)测试 -->
  <dependency>
    <groupId>org.apache.flink</groupId>
    <artifactId>flink-test-utils-junit</artifactId>
    <version>${flink.version}</version>
    <scope>test</scope>
  </dependency>
  <dependency>
    <groupId>org.junit.jupiter</groupId>
    <artifactId>junit-jupiter</artifactId>
    <version>5.10.2</version>
    <scope>test</scope>
  </dependency>
</dependencies>

五、构建与入口类

打包命令:

bash 复制代码
mvn clean package

产物位于 target/<artifact-id>-<version>.jar。

入口类(mainClass) :若主类不是默认 DataStreamJob,请在 pom.xml 的打包配置(或 Shade 的 ManifestResourceTransformer)里设置 mainClass,提交 JAR 时就无需再手动 -c 指定。

六、何时需要 uber/fat JAR?

  • 仅用 Flink 自带能力(如 filesystem + JSON) → 不需要 uber JAR,可直接提交普通 JAR。
  • 引入外部依赖/连接器(发行版未内置) →
    (一)把依赖放进集群 classpath ;
    (二)Shade 成 uber/fat JAR(推荐,分发更简单)。

提交示例:

bash 复制代码
bin/flink run -c org.example.MyJob myFatJar.jar

七、Maven Shade 插件模板(可直接粘贴)

xml 复制代码
<build>
  <plugins>
    <plugin>
      <groupId>org.apache.maven.plugins</groupId>
      <artifactId>maven-shade-plugin</artifactId>
      <version>3.1.1</version>
      <executions>
        <execution>
          <phase>package</phase>
          <goals><goal>shade</goal></goals>
          <configuration>
            <artifactSet>
              <excludes>
                <exclude>com.google.code.findbugs:jsr305</exclude>
              </excludes>
            </artifactSet>
            <filters>
              <filter>
                <!-- 不拷贝签名,避免 SecurityException -->
                <artifact>*:*</artifact>
                <excludes>
                  <exclude>META-INF/*.SF</exclude>
                  <exclude>META-INF/*.DSA</exclude>
                  <exclude>META-INF/*.RSA</exclude>
                </excludes>
              </filter>
            </filters>
            <transformers>
              <!-- 替换为你的主类 -->
              <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
                <mainClass>my.programs.main.clazz</mainClass>
              </transformer>
              <transformer implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer"/>
            </transformers>
          </configuration>
        </execution>
      </executions>
    </plugin>
  </plugins>
</build>

Shade 默认会打包 compile 与 runtime 作用域依赖;provided 不会被打进 JAR。

八、实用小贴士与常见坑

小贴士

(1)IntelliJ 运行作业:勾选 Include dependencies with "Provided" scope ,否则本地跑可能找不到 Flink 运行时类。

(2)连接器版本与 Flink 版本 对齐,避免 classpath 冲突。

(3)固定入口类:减少提交参数,降低运维摩擦。

常见坑

(1)JAR 体积巨大或冲突 :把 flink-clients/table-runtime/planner-loader 打进了 JAR → 改成 provided。

(2)NoSuchMethodError / ClassNotFound :连接器没被 shade 进来或版本不匹配 → 查 dependency:tree 并调整。

(3)IDE 能跑,集群失败 :集群侧缺少匹配版本运行时模块 → 对齐集群与本地依赖。

(4)老 IntelliJ 无 provided 选项 :用测试用例调用 main() 代跑。

(5)主类不对导致提交失败 :pom.xml 未配置 mainClass 或写错 → 在 Shade Manifest 中显式指定。

九、你的下一步

(1)挑一个最小作业(Kafka → 清洗 → Sink),补齐 API + 连接器 依赖。

(2)用 Shade 打出一个 uber JAR ,在本地与测试集群各跑一遍。

(3)把打包与提交接入 CI/CD(构建、制品库、部署到 Session/Application Cluster)。

把依赖作用域分得清、Shade 配置写得对、入口类设得明白,你的 Flink 项目就能顺滑地在本地开发、CI 构建与集群部署之间切换。祝你首个 Maven 驱动的 Flink 作业上线顺利!

相关推荐
Wang's Blog21 分钟前
Java框架 SpringCloud 快速入门: 实现 Feign 最佳实践(抽取方式)
java·spring cloud
MandalaO_O1 小时前
IDEA 开发(快捷键 + 调试 + 序列化)
java·ide·intellij-idea
xiaoqiMikko2 小时前
JVM 线上排查实战(七):jps 看不见它、jstack 连不上它,可它明明活得好好的
java·jvm
狼爷3 小时前
Rust/Go/Java/Python/PHP 大比拼:负载下后端框架到底差多少?
java·后端·编程语言
念何架构之路3 小时前
zap扩展生态与总结
java·前端·数据库
第七页独白3 小时前
汽车零件厂如何通过 QMS 真正落地 IATF 16949——QMS软件系统:品质检验-内审稽核-8d客诉管理:全星质量管理软件系统
java·前端·数据库
QCoding4 小时前
Spring AI Alibaba Graph实战:从ReAct Agent到Workflow,企业AI复杂流程该如何编排?
java·人工智能
用户094248568034 小时前
第25章:Java虚拟线程(Project Loom)实战与调度协作
java·jvm
砚底藏山河4 小时前
量化实战:截面因子有效性检验(IC 分析与分层回测)
java·python·金融·maven
wuminyu4 小时前
ForkJoinPool内部WorkQueue的Lock-Free数组操作以及并发任务窃取原理剖析
java·linux·c语言·jvm·c++