用 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 作业上线顺利!

相关推荐
古法老登瞎折腾1 小时前
大数据智能运维实战(十一):运维 MCP 的工程化——权限、限流、审计与错误处理
java·大数据·运维·spring ai·mcp
智能运维指南2 小时前
研制过程“两张皮“怎么破:研制一体化支撑平台的定位、能力边界与落地前提
java·前端·人工智能·嘉为蓝鲸
yz_aiks3 小时前
Spring AI 2.1 ChatMemory 已过时用什么替代:迁移到 Session Memory 实战(JDBC 存储与会话压缩)
java·spring boot·大模型·ai agent·spring ai
金銀銅鐵3 小时前
[Java] 用 GUI 展示 EnumMap 增删键值对时的内部变化
java·后端·ai编程
学长毕设3 小时前
基于SpringBoot的上门洗车服务系统设计与实现
java·spring boot·后端
jason成都3 小时前
RTKLIB-Java 多基线联合RTK:FIX率从0%到91.5%的三层根因修复
java·gnss·rtklib·rtklib_java
鱼宵3 小时前
Stream 终端操作一次讲透:collect、count、reduce 怎么选
java·stream·终端操作
白山编程大哥3 小时前
Java 后端如何优雅地把 List 集合返回给前端
java·前端·list
Linux运维技术栈4 小时前
CVE-2026-91403 高危漏洞修复:Rocky Linux 9 多版本 JDK 环境清理实操
java·linux·运维
On The Road :4 小时前
Java 多线程详解:从入门到线程安全
java·python·安全