Description

一段简单的 FlinkSQL 程序,在 IDE 中运行没问题,但是 maven 打包后发布到终端启动却报错了。

import org.apache.flink.configuration.Configuration;
import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;
import org.apache.flink.table.api.StatementSet;
import org.apache.flink.table.api.bridge.java.StreamTableEnvironment; public class FlinkSQL { public static void main(String[] args) throws Exception {
Configuration configuration = new Configuration();
configuration.setInteger("rest.port", 9091);
StreamExecutionEnvironment env = StreamExecutionEnvironment.createLocalEnvironmentWithWebUI(configuration);
StreamTableEnvironment tableEnv = StreamTableEnvironment.create(env); String createSourceTableSQL = "CREATE TABLE source_dest (" +
"`id` INT," +
"`player` STRING," +
"`team` STRING," +
"`score` INT," +
"PRIMARY KEY (`id`) NOT ENFORCED" +
") WITH (" +
"'connector' = 'mysql-cdc'," +
"'hostname' = '10.4.45.207'," +
"'username' = 'username'," +
"'password' = 'password'," +
"'database-name' = 'cdc_test_source'," +
"'table-name' = 'player_scores'," +
"'scan.startup.mode' = 'latest-offset'" +
");";
tableEnv.executeSql(createSourceTableSQL); String createSinkTableSQL = "CREATE TABLE sink_dest (" +
"`id` INT," +
"`player` STRING," +
"`team` STRING," +
"`score` INT," +
"PRIMARY KEY (`id`) NOT ENFORCED" +
") WITH (" +
"'connector' = 'jdbc'," +
"'url' = 'jdbc:mysql://10.4.45.207:3306/cdc_test_target'," +
"'username' = 'username'," +
"'password' = 'password'," +
"'table-name' = 'player_scores'" +
");";
tableEnv.executeSql(createSinkTableSQL); String insertSQL = "INSERT INTO sink_dest SELECT * FROM source_dest;";
StatementSet statementSet = tableEnv.createStatementSet();
statementSet.addInsertSql(insertSQL);
statementSet.execute();
}
}

maven 的 pom.xml

<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.example</groupId>
<artifactId>flink-learning</artifactId>
<version>0.0.1-SNAPSHOT</version>
<description>flink</description> <properties>
<scala.binary.version>2.12</scala.binary.version>
<flink.version>1.15.4</flink.version>
</properties> <dependencies>
<dependency>
<groupId>org.apache.flink</groupId>
<artifactId>flink-java</artifactId>
<version>${flink.version}</version>
</dependency>
<dependency>
<groupId>org.apache.flink</groupId>
<artifactId>flink-runtime-web</artifactId>
<version>${flink.version}</version>
</dependency>
<dependency>
<groupId>org.apache.flink</groupId>
<artifactId>flink-table-api-java-bridge</artifactId>
<version>${flink.version}</version>
</dependency>
<dependency>
<groupId>org.apache.flink</groupId>
<artifactId>flink-table-runtime</artifactId>
<version>${flink.version}</version>
</dependency>
<dependency>
<groupId>org.apache.flink</groupId>
<artifactId>flink-table-planner-loader</artifactId>
<version>${flink.version}</version>
</dependency>
<dependency>
<groupId>org.apache.flink</groupId>
<artifactId>flink-connector-base</artifactId>
<version>${flink.version}</version>
</dependency>
<dependency>
<groupId>org.apache.flink</groupId>
<artifactId>flink-connector-jdbc</artifactId>
<version>${flink.version}</version>
</dependency>
<dependency>
<groupId>com.ververica</groupId>
<artifactId>flink-connector-mysql-cdc</artifactId>
<version>2.4.0</version>
</dependency>
</dependencies> <build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.1.1</version>
<configuration>
<createDependencyReducedPom>false</createDependencyReducedPom>
</configuration>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<filters>
<filter>
<!-- Do not copy the signatures in the META-INF folder. Otherwise,
this might cause SecurityExceptions when using the JAR. -->
<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>org.example.test.FlinkSQL</mainClass>
</transformer>
</transformers>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

使用 maven-shade-plugin 打包成 jar 后,直接使用 java -jar 命令启动,遇到报错:

Exception in thread "main" org.apache.flink.table.api.TableException: Could not instantiate the executor. Make sure a planner module is on the classpath
at org.apache.flink.table.api.bridge.internal.AbstractStreamTableEnvironmentImpl.lookupExecutor(AbstractStreamTableEnvironmentImpl.java:108)
at org.apache.flink.table.api.bridge.java.internal.StreamTableEnvironmentImpl.create(StreamTableEnvironmentImpl.java:100)
at org.apache.flink.table.api.bridge.java.StreamTableEnvironment.create(StreamTableEnvironment.java:122)
at org.apache.flink.table.api.bridge.java.StreamTableEnvironment.create(StreamTableEnvironment.java:94)
at org.example.test.FlinkSQL.main(FlinkSQL.java:19)
Caused by: org.apache.flink.table.api.ValidationException: Could not find any factories that implement 'org.apache.flink.table.delegation.ExecutorFactory' in the classpath.
at org.apache.flink.table.factories.FactoryUtil.discoverFactory(FactoryUtil.java:526)
at org.apache.flink.table.api.bridge.internal.AbstractStreamTableEnvironmentImpl.lookupExecutor(AbstractStreamTableEnvironmentImpl.java:105)
... 4 more

Locate

找不到 org.apache.flink.table.delegation.ExecutorFactory 的实现类?

跟踪源码查看一下:

step into 继续跟进

step into 继续跟进

到这里就很明确了,原来是找不到 SPI 的实现类。SPI 的加载路径是 META-INF/services, 打开 jar 包查看一下:

org.apache.flink.table.factories.Factory 中只有 3 个注册的 class, 其中确实没有 org.apache.flink.table.delegation.ExecutorFactory 的实现类。

IDE 中可以运行,打包后出现异常,说明是打包过程出现了问题。

排查后发现,项目中的依赖中存在不止一个 org.apache.flink.table.factories.Factory 的 SPI:

而使用 maven-shade-plugin 打包时,默认将第一个依赖 (flink-table-api-java-bridge.jar)中的 META-INF/services 打包进来,并忽略了其他依赖中存在的同名 SPI。

Fixed

我们希望将所有依赖中存在的同名 SPI 中的内容进行 merge,Flink 官方文档 给出了解决办法:

Flink uses Java's Service Provider Interfaces (SPI) to load the table connector/format factories by their identifiers. Since the SPI resource file named org.apache.flink.table.factories.Factory for every table connector/format is under the same directory META-INF/services, these resource files will override each other when build the uber-jar of the project which uses more than one table connector/format, which will cause Flink to fail to load table connector/format factories.

实际上只需要给 maven-shade-plugin 添加一项配置:

<!-- The service transformer is needed to merge META-INF/services files -->
<transformer implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer">
</transformer>

重新打包,验证一下:

重新启动程序:

java -jar flink-learning-0.0.1-SNAPSHOT.jar

运行成功:

【Flink 日常踩坑】Could not find ExecutorFactory in classpath的更多相关文章

  1. 日常踩坑 — 相邻元素之间的margin合并问题。

    踩坑:使用v-for渲染的组件,当然图中的id已经换成class,还是没有解决这个问题,于是各种查找资料,我就不信简单的CSS问题这么难解决! v-for渲染组件级传值: <div class= ...

  2. 日常踩坑 searter

    目录 es7中的async, await Django生成二维码并转为base64 Django配置404页面 很傻逼的坑 no module named pil 其他 es7中的async, awa ...

  3. 日常踩坑——Dev C++ pow()函数的坑

    坑 Dev C++ pow()函数 那年冬天,显示屏前坐着如喽啰,那时候我含泪发誓,再也不用Dev. 蓝桥杯官网给提供的版本,没办法bug也得硬着头皮用. 16年蓝桥杯的第八题 四平方和定理: 在De ...

  4. 日常踩坑-------新手使用idea

    mybatis在idea的maven项目中的坑 今天遇到mybatis的报错,搞了好久才搞懂,在网上找了好久的相似案例,也没有搞定,先来看下网上常见的解决办法吧,相信也能解决大部分人的报错. 1.ma ...

  5. 日常踩坑笔记:spring的context:property-placeholder标签

    背景: 原来的项目一直跑着没有问题,今天突然想在原有项目的基础上,加上redis进行数据的缓存,原来项目的架构就是传统的SSM框架,于是,大刀阔斧的开始改装了... 编写redis的配置文件——red ...

  6. 日常踩坑——rand()总是出现重复数据

    写了一个生成随机数组的函数,然后跑出来,结果总是…… 然后,很奇怪的是一步一步调试,它就没问题了,WTF??? 问题出在:重复写了srand(time(NULL)),只保留一个就好了. int* ge ...

  7. 【React Native】日常踩坑记录_以后将持续更新

    作为一名有理想.有抱负的一代iOS程序员,本着“我头发够多,还能学”的原则,我选择了追随那些大佬的脚步,于2018年开始了React Native. 第一步:找文档.准备安装开发环境: 第二步:一步步 ...

  8. 『vue踩坑日常』 在index.html中引入静态文件不生效

    Vue日常踩坑日常 -- 在index.html中引入静态文件不生效问题 本文针对的是Vue小白,不喜勿喷,谢谢 出现该问题的标志如下 控制台warning(Resource interpreted ...

  9. Vue packages version mismatch的解决方法 初来乍到,踩坑日常

    初来乍到,踩坑日常 这个问题也是我也是接受别人项目,出现的问题,在下载好依赖后运行的时候报这样的错误 它上面显示两个版本一个vue的版本,一个vue-template-compiler版本,我这边忘了 ...

  10. Java 开发中如何正确踩坑

    为什么说一个好的员工能顶 100 个普通员工 我们的做法是,要用最好的人.我一直都认为研发本身是很有创造性的,如果人不放松,或不够聪明,都很难做得好.你要找到最好的人,一个好的工程师不是顶10个,是顶 ...

随机推荐

  1. esp32挂esphome

    esp32挂esphome 使用docker创建容器 docker run -d --name='esphome' \ --restart=always \ -p 6052:6052 \ -e TZ= ...

  2. element UI el-table 合并单元格

    效果图如下: template 代码: <el-table ref="fundBalanceDailyReportTable" :span-method="obje ...

  3. JDK有用的新特性-Java Record

    目录 Java Record Record使用 Instance Methods 静态方法 Static Method Record 的构造方法 step1: 紧凑和定制构造方法 Record 与 与 ...

  4. manim边学边做--曲线类

    manim中曲线,除了前面介绍的圆弧类曲线,也可以绘制任意的曲线. manim中提供的CubicBezier模块,可以利用三次贝塞尔曲线的方式绘制任意曲线. 关于贝塞尔曲线的介绍,可以参考:https ...

  5. DOM & BOM – 冷知识 (新手)

    JS 无法 query select 到伪元素 参考: 使用JS控制伪元素的几种方法 JS style remove property 是 kebab-case set property 是 came ...

  6. LeetCode 1388. Pizza With 3n Slices(3n 块披萨)(DP)

    给你一个披萨,它由 3n 块不同大小的部分组成,现在你和你的朋友们需要按照如下规则来分披萨: 你挑选 任意 一块披萨.Alice 将会挑选你所选择的披萨逆时针方向的下一块披萨.Bob 将会挑选你所选择 ...

  7. python:批量删除指定文件目录中多个文件

    #coding:utf-8# 任务需要,需要删除多余的文件,手动删除太麻烦,几行python搞定 import os from glob import glob path = r"/medi ...

  8. 分类问题的评价指标AUC

  9. react -- 什么是jsx

    概念:JSX 就是js和xml的缩写,表示在js代码中编写html模板结构,他是react中编写UI模板的方式 优势:html的声明式模板写法  js的可编程能力

  10. kotlin更多语言结构——>This表达式

    This表达式 为了表示当前的 接收者 我们使用 this 表达式: - 在类的成员中,this指的是该类的当前对象. - 在扩展函数或者带有接收者的函数字面值中,this 表示在点左侧传递的 接收者 ...