Flink 自定义addSource 后 SourceFunction 的 run 方法如何执行?源码分析。

正片文章分两个阶段来分析。
第一阶段在 AbstractUdfStreamOperator 中将 userFunction 指向 UserDefineSource, env.addSource(new UserDefineSource) 为入口。
第二阶段在 StreamSource 中 通过 userFunction.run() 调用了 UserDefineSource 中的 run 方法。

第一阶段

  1. 用户自定义的类
    def main(args: Array[String]): Unit = {
        val env: StreamExecutionEnvironment = StreamExecutionEnvironment.getExecutionEnvironment
        // 注册自定义 SourceFunction 类到 StreamExecutionEnvironment
        val uds: DataStream[SensorReading] = env.addSource(new UserDefineSource) // ⭐️⭐️⭐️ 此处开始分析
        uds.print("ReadFromUDS Test")
        env.execute()
    }

    class UserDefineSource extends SourceFunction[SensorReading] {

        var running: Boolean = true

        override def run(ctx: SourceFunction.SourceContext[SensorReading]): Unit = {
            //模拟随机数据, 可以是其他源 mysql, redis, elastic search, ...
            val random: Random = new Random()
            //初始温度
            val initTemp: immutable.IndexedSeq[(String, Double)] = 1.to(10).map(
                i => {
                    ("sensor_" + i, random.nextDouble() * 100)
                }
            )
            while (running) {
                //将上次数据温度值微调,生成当前温度
                val curTemp: immutable.IndexedSeq[(String, Double)] = {
                    initTemp.map(
                        data => (data._1, data._2 + random.nextGaussian())
                    )
                }
                // 生成 数据产生的时间戳
                val curTime: Long = System.currentTimeMillis()
                //数据放入 SourceContext 中。
                curTemp.foreach(
                    data => {
                        ctx.collect(SensorReading(data._1, curTime, data._2))
                    }
                )
                Thread.sleep(2000)
            }
        }

        override def cancel(): Unit = {
            running = false
        }
    }

  1. StreamExecutionEnvironment
    在这里插入图片描述

  2. StreamExecutionEnvironment
    在这里插入图片描述

  3. StreamExecutionEnvironment
    在这里插入图片描述

  4. StreamSource
    在这里插入图片描述

  5. AbstractUdfStreamOperator
    在这里插入图片描述


第一阶段结束。 以上 userFunction 就指向我们自定义的 SourceFunction 子类 UserDefineSource


第二阶段

执行任务时调用 run 方法。

env.execute() 执行后,就会经过一系类操作后,在 SourceStreamTask 启动一个线程。

此处一系列操作主要是通过反射进行的。为了简化问题此处省略这一过程。

Task ( run()  -> doRun() -> invokable.invoke() -> runMailboxLoop() ) 
=> StreamTask( mailboxProcessor.runMailboxLoop()  )     
=> MailboxProcessor (mailboxDefaultAction.runDefaultAction(defaultActionContext) ) 
=>SourceStreamTask ( processInput() )
=> 接下面 👇 分析
  1. SourceStreamTask
private final LegacySourceFunctionThread sourceThread;

在这里插入图片描述
在这里插入图片描述

  1. StreamSource

在这里插入图片描述
在这里插入图片描述

/** The user function. */
protected final F userFunction;
  1. 这个 userFunction 就是我们第一阶段分析的,指向我们自定义的 SourceFunction 子类 UserDefineSource

类结构图如下:
在这里插入图片描述

第一阶段在 AbstractUdfStreamOperator 中将 userFunction 指向 UserDefineSource
第二阶段在 StreamSource 中 通过 userFunction.run() 调用了 UserDefineSource 中的 run 方法。

至此,自定义 Source 的 UserDefineSource 中 run 方法的执行过程就清楚了。

©️2020 CSDN 皮肤主题: 编程工作室 设计师:CSDN官方博客 返回首页