1 原因分析
这个报错一般会有两种情况:
- map过程中存在的POJO类没有定义完善,缺少公有构造函数定义等
- 使用Scala编码时,Flink接入的Kafka数据,不能使用幂名函数进行操作,只能自定义函数进行对DS的处理
2 对应的解决办法
2.1 对POJO类进行完整定义
使用@Lombok对class进行注解
2.2 查看是否StreamingExecutionEnviroment导错
JAVA程序对应的Enviroment导入:
import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;
Scala程序对应的Enviromment导入:
import org.apache.flink.streaming.api.scala.StreamExecutionEnvironment
3 那为什么引用不同的类就会报错呢
底层的原因是什么呢?我带着这个好奇心去源码里面看了一下。
入口函数:
val environment: StreamExecutionEnvironment = StreamExecutionEnvironment
.createLocalEnvironmentWithWebUI()
函数点击进去看到函数签名(进入到org.apache.flink.streaming.api.scala.StreamExecutionEnvironment):
/**
* Creates a [[StreamExecutionEnvironment]] for local program execution that also starts the
* web monitoring UI.
*
* The local execution environment will run the program in a multi-threaded fashion in
* the same JVM as the environment was created in. It will use the parallelism specified in the
* parameter.
*
* If the configuration key 'rest.port' was set in the configuration, that particular
* port will be used for the web UI. Otherwise, the default port (8081) will be used.
*
* @param config optional config for the local execution
* @return The created StreamExecutionEnvironment
*/
@PublicEvolving
def createLocalEnvironmentWithWebUI(config: Configuration = null): StreamExecutionEnvironment = {
val conf: Configuration = if (config == null) new Configuration() else config
//调用JAVAEnv创建一个JavaEnv返回。
//那么这个错误会和哪里有关系呢?
new StreamExecutionEnvironment(JavaEnv.createLocalEnvironmentWithWebUI(conf))
}
点进来一看,这里没有什么问题呀,这里也确实没有问题。那么问题在哪呢
真正的问题根源:
/**
* Create a DataStream using a user defined source function for arbitrary
* source functionality. By default sources have a parallelism of 1.
* To enable parallel execution, the user defined source should implement
* ParallelSourceFunction or extend RichParallelSourceFunction.
* In these cases the resulting source will have the parallelism of the environment.
* To change this afterwards call DataStreamSource.setParallelism(int)
*
*/
def addSource[T: TypeInformation](function: SourceFunction[T]): DataStream[T] = {
require(function != null, "Function must not be null.")
//寻找闭包函数,这个是常规操作
val cleanFun = scalaClean(function)
//重头戏是这个隐式的implicitly[TypeInformation[T]]
val typeInfo = implicitly[TypeInformation[T]]
asScalaStream(javaEnv.addSource(cleanFun, typeInfo))
}
implicit转换,我肤浅的理解是找到对应的定义。例如这个例子当中的TypeInformation[T],就是找到对应的TypeInfo,然后传递。
4、揭开谜底
那么谜底是啥呢,谜底就是Flink自己定义好了好多TypeInfo等着套,或者说定义了一个类型完备的TypeInfo集合(因为我现在还没有遇到没匹配到的,遇到了我再更新这句话)。
下面这张图片里面包含了所有的TypeInfo实现类。如果是下次引入类型不对,可以进去到源码看看哪里对应不上。