用 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-clientsflink-table-runtimeflink-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
    (二)Shadeuber/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 默认会打包 compileruntime 作用域依赖;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 作业上线顺利!

相关推荐
码智社7 小时前
AES加密原理详解及Java实现加解密实战
java·开发语言
萧瑟余晖8 小时前
JDK 26 新特性详解
java·开发语言
马优晨8 小时前
Freemarker 完整讲解(后端 Java 模板引擎)
java·开发语言·freemarker·freemarker 完整讲解·freemarker模板引擎
维天说11 小时前
CLI-Switch 2026年3月版历史设计:Hook、TTY 隔离与 JSON 状态
java·服务器·json
Zane199412 小时前
并发 vs 并行:别再傻傻分不清了,一文讲透 Java 并发编程的第一课
java·后端
噢,我明白了13 小时前
java中Excel的导入和导出(EasyExcel)
java·开发语言·excel
吠品13 小时前
Zabbix Web界面误报Server未运行的排查与解决
java·服务器·数据库
啊湘13 小时前
天气查询API接口 按月Token鉴权 实时天气 物联网可用 文档齐全
java·后端·struts
Java内核笔记13 小时前
告别十亿美元的错误 : Spring Boot 4 空安全 (JSpecify) 实战
java·spring boot·后端
糖果店的幽灵13 小时前
langgraph的 MessagesState 解读
java·开发语言·人工智能·windows·langgraph