【Flink 日常踩坑】Could not find ExecutorFactory in classpath

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的更多相关文章
- 日常踩坑 — 相邻元素之间的margin合并问题。
踩坑:使用v-for渲染的组件,当然图中的id已经换成class,还是没有解决这个问题,于是各种查找资料,我就不信简单的CSS问题这么难解决! v-for渲染组件级传值: <div class= ...
- 日常踩坑 searter
目录 es7中的async, await Django生成二维码并转为base64 Django配置404页面 很傻逼的坑 no module named pil 其他 es7中的async, awa ...
- 日常踩坑——Dev C++ pow()函数的坑
坑 Dev C++ pow()函数 那年冬天,显示屏前坐着如喽啰,那时候我含泪发誓,再也不用Dev. 蓝桥杯官网给提供的版本,没办法bug也得硬着头皮用. 16年蓝桥杯的第八题 四平方和定理: 在De ...
- 日常踩坑-------新手使用idea
mybatis在idea的maven项目中的坑 今天遇到mybatis的报错,搞了好久才搞懂,在网上找了好久的相似案例,也没有搞定,先来看下网上常见的解决办法吧,相信也能解决大部分人的报错. 1.ma ...
- 日常踩坑笔记:spring的context:property-placeholder标签
背景: 原来的项目一直跑着没有问题,今天突然想在原有项目的基础上,加上redis进行数据的缓存,原来项目的架构就是传统的SSM框架,于是,大刀阔斧的开始改装了... 编写redis的配置文件——red ...
- 日常踩坑——rand()总是出现重复数据
写了一个生成随机数组的函数,然后跑出来,结果总是…… 然后,很奇怪的是一步一步调试,它就没问题了,WTF??? 问题出在:重复写了srand(time(NULL)),只保留一个就好了. int* ge ...
- 【React Native】日常踩坑记录_以后将持续更新
作为一名有理想.有抱负的一代iOS程序员,本着“我头发够多,还能学”的原则,我选择了追随那些大佬的脚步,于2018年开始了React Native. 第一步:找文档.准备安装开发环境: 第二步:一步步 ...
- 『vue踩坑日常』 在index.html中引入静态文件不生效
Vue日常踩坑日常 -- 在index.html中引入静态文件不生效问题 本文针对的是Vue小白,不喜勿喷,谢谢 出现该问题的标志如下 控制台warning(Resource interpreted ...
- Vue packages version mismatch的解决方法 初来乍到,踩坑日常
初来乍到,踩坑日常 这个问题也是我也是接受别人项目,出现的问题,在下载好依赖后运行的时候报这样的错误 它上面显示两个版本一个vue的版本,一个vue-template-compiler版本,我这边忘了 ...
- Java 开发中如何正确踩坑
为什么说一个好的员工能顶 100 个普通员工 我们的做法是,要用最好的人.我一直都认为研发本身是很有创造性的,如果人不放松,或不够聪明,都很难做得好.你要找到最好的人,一个好的工程师不是顶10个,是顶 ...
随机推荐
- Mac 删除 Steam 游戏图标
Steam 将游戏安装在了 ~/Applications,打开访达,前往该目录,将相关游戏移到废纸篓.
- ServletConfig 类和ServletContext 类
ServletConfig 类 ServletConfig 类从类名上来看,就知道是 Servlet 程序的配置信息类. Servlet 程序和 ServletConfig 对象都是由 Tomcat ...
- 受 LabelImg 启发的基于 web 的图像标注工具,基于 Vue 框架
受 LabelImg 启发的基于 web 的图像标注工具,基于 Vue 框架 哟,网友们好,年更鸽子终于想起了他的博客园密码.如标题所述,今天给大家带来的是一个基于 vue2 的图像标注工具.至于 ...
- C++ | 每一个C++程序员都应该知道的RAII
导读:RAII是C++中一种管理资源.避免资源泄漏的惯用法,利用栈的特点来实现.本文较为详细介绍了RAII的原理.使用方法和优点,并且通过实例讲解了RAII在C++ STL中的应用,如智能指针和互斥锁 ...
- DOM – Dimension & Coordinate (offset, client, computed, rect)
前言 很多年前有记入过一篇 box-sizing 和 dom width. 想想也挺可悲的, 那年我是负责后端的, 却要帮着前端去学习这些知识来解决问题... 也好, 现在 full stack, 也 ...
- c语言 宏的一些深层应用(##,#,宏函数)
"##" 宏拼接 #define CONCATENATE(a, b) a ## b CONCATENATE(student_, 1) // 将a和b拼接起来变成一个新的变量 -&g ...
- SpringMVC —— 入门案例执行流程
启动服务器初始化过程 1.服务器启动,执行ServletContainersInitConfig类,初始化web容器 2.执行createServletApplicationContext方法, ...
- Flutter 3.3 正式发布
Flutter 3 是我们正式为全平台提供支持的一个重量级里程碑,距离它的发布仅过去了三个月,今天让我们有请 Flutter 3.3 正式版!近三个月我们并没有放慢更新迭代的速度--自 Flutter ...
- C#|.net core 基础 - 深拷贝的五大类N种实现方式
在实际应用中经常会有这样的需求:获取一个与原对象数据相同但是独立于原对象的精准副本,简单来说就是克隆一份,拷贝一份,复制一份和原对象一样的对象,但是两者各种修改不能互相影响.这一行为也叫深克隆,深拷贝 ...
- 反问面试官3个ThreadLocal的问题
ThreadLocal,一个Java人面试绕不开的话题,我也很奇怪为什么那些面试官很喜欢问这个,也不知道他们自己有没有搞清楚. 接下来,我想先说说ThreadLocal的用法和使用场景,然后反问面试官 ...