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 方法的执行过程就清楚了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值