Flink 程序Sink(数据输出)操作(5)自定义RabbitMq-Sink

Flink 程序Sink(数据输出)操作(5)自定义RabbitMq-Sink

自定义sink需要继承RichSinkFunction

ex:

public static class Demo extends RichSinkFunction<IN> {}

自定义RabbitMQ sink必要依赖

<dependency>
    <groupId>org.apache.flink</groupId>
    <artifactId>flink-connector-rabbitmq_2.12</artifactId>
    <version>1.12.2</version>
</dependency>

如上依赖所示,其实已经是有rabbitMQ的连接器,但是,此连接器只能简单的Queue 模式,我们的业务需求可能不能直接使用Queue模式,比如需要发送到交换机中(Fanout、Driect)等。如果有这种场景呢,我们需要连接器的基础上再自定义RabbitMQ Sink了。

定义配置

# 计算结果输出RabbitMQ配置
sink.rabbitmq.host=10.50.40.116
sink.rabbitmq.port=5673
sink.rabbitmq.username=admin
sink.rabbitmq.password=admin
sink.rabbitmq.exchange=vehicle-alarm-over-speeding

配置对应实体类

我们一会使用代码,读取我们的sink配置为对象,作为参数不断传递

@NoArgsConstructor
@AllArgsConstructor
@Builder
@Data
public class RabbitMqSinkProperties implements Serializable {
    /**
     * rabbitMQ ip
     */
    private String host;
    /**
     * 端口
     */
    private int port;
    /**
     * 用户民
     */
    private String userName;
    /**
     * 密码
     */
    private String passWord;
    /**
     * 交换机名
     */
    private String exchange;


}

定义公共MQSink类继承RichSinkFunction

此类主要作用是作为一个RabbitMQ sink的中间模板,其中定义MQ sink 与RabbitMQ 的连接与关闭,交换机的类型指定等等。

我们某个具体的MQ sink 只需要继承此中间模板类,传输我们之前定义的配置对象,即可快速在invoke中完成对RabbitMQ数据的输出

package com.leilei.sink;

import com.rabbitmq.client.BuiltinExchangeType;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import lombok.extern.slf4j.Slf4j;
import org.apache.flink.configuration.Configuration;
import org.apache.flink.streaming.api.functions.sink.RichSinkFunction;

/**
 * @author lei
 * @version 1.0
 * @desc mq 公共模板类 我们我们如果有多个mq-sink  只需继承此类 即可
 * @date 2021-03-15 16:41
 */
@Slf4j
public class DataRichSinkFunction<IN> extends RichSinkFunction<IN> {

    // 配置对象  后续我们在定义具体实体类时用子类触发父类构造调用
    protected final RabbitMqSinkProperties rabbitMQSinkProperties;


    protected Connection connection;

    protected Channel channel;

    public DataRichSinkFunction(RabbitMqSinkProperties rabbitMQSinkProperties) {
        this.rabbitMQSinkProperties = rabbitMQSinkProperties;
    }


    /**
     * open() 方法中建立连接,这样不用每次 invoke 的时候都要建立连接和释放连接
     *
     * @param parameters
     * @throws Exception
     */
    @Override
    public void open(Configuration parameters) throws Exception {
        super.open(parameters);
        // 创建连接工厂
        ConnectionFactory factory = new ConnectionFactory();

        // 设置RabbitMQ相关信息
        factory.setHost(rabbitMQSinkProperties.getHost());
        factory.setUsername(rabbitMQSinkProperties.getUserName());
        factory.setPassword(rabbitMQSinkProperties.getPassWord());
        factory.setPort(rabbitMQSinkProperties.getPort());

        // 创建一个新的连接
        connection = factory.newConnection();

        // 创建一个通道
        channel = connection.createChannel();

        // 声明交换机
        channel.exchangeDeclare(rabbitMQSinkProperties.getExchange(), BuiltinExchangeType.FANOUT, true);
    }

    /**
     * 关闭连接 flink程序从启动到销毁只会执行一次
     * @throws Exception
     */
    @Override
    public void close() throws Exception {
        super.close();
        channel.close();
        connection.close();
    }

}

根据业务定义sink类继承公共MQSink模板

由于公共MQSink模板类中已经对rabbitMq做了一个连接通道的开启和关闭,因此我们当前sink无需关系自身与Mq的连接与关闭,直接在invoke方法中,将数据输出到Mq即可

public class DemoSinkFunction extends DataRichSinkFunction<String> {

    public OverSpeedAlarmSinkFunction(RabbitMqSinkProperties rabbitMQSinkProperties) {
         /**
         * 调用父类(DataRichSinkFunction)构造,完成父类中属性填充
         */
        super(rabbitMQSinkProperties);
    }
    /**
     * 数据输出到 rabbitMQSinkProperties 指定的交换机中
     * @param value
     * @param context
     * @throws Exception
     */
    @Override
    public void invoke(String value, Context context) throws Exception {
        System.out.println(LocalDateTime.now() + "发送数据:" + value);
        channel.basicPublish(rabbitMQSinkProperties.getExchange(), "", null, value.getBytes(StandardCharsets.UTF_8));
    }
}

输出测试

StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
env.setRuntimeMode(RuntimeExecutionMode.STREAMING);
//自定义数据源加载 
DataStreamSource<Location> source = env.addSource(new MyLocationSource());
//读取rabbitMq sink配置文件
String path = "RabbitMqSink.properties";
Props props = new Props(path);
RabbitMqSinkProperties sinkProperties = RabbitMqSinkProperties.builder()
    .host(props.getStr("sink.rabbitmq.host"))
    .port(props.getInt("sink.rabbitmq.port"))
    .userName(props.getStr("sink.rabbitmq.username"))
    .passWord(props.getStr("sink.rabbitmq.password"))
    .exchange(props.getStr("sink.rabbitmq.exchange"))
    .build();

// TODO  source进行数据处理 得到结果流
//将结果流用自定义的sink发送到rabbitmq
stream.addSink(new DemoSinkFunction(sinkProperties));

image-20210412204206021

image-20210412204224515

从控制台打印以及RabbitMQ-WEB页面看到,我们计算的结果,成功发送到了RabbitMQ的自定义交换机中, RabbitMQ SInk 示例完成!

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Flink 提供了自定义 Sink 的功能,可以让用户根据自己的需求实现自己的 Sink 函数。自定义 Sink 主要涉及两个步骤:实现一个继承自 `RichSinkFunction` 的类,并重写其中的方法;在 Flink 程序中使用自定义 Sink。 以下是一个简单的示例,展示如何自定义一个 Sink 函数: 首先,创建一个类继承自 `RichSinkFunction`: ```java public class CustomSink extends RichSinkFunction<String> { @Override public void invoke(String value, Context context) throws Exception { // 自定义的逻辑处理,这里示例只打印输出 System.out.println(value); } } ``` 然后,在 Flink 程序中使用自定义 Sink: ```java public class CustomSinkExample { public static void main(String[] args) throws Exception { StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment(); DataStream<String> stream = env.fromElements("message 1", "message 2", "message 3"); // 使用自定义Sink stream.addSink(new CustomSink()); env.execute("Custom Sink Example"); } } ``` 在上述示例中,自定义Sink 函数 `CustomSink` 继承自 `RichSinkFunction`,并实现了 `invoke` 方法,其中可以编写自己的数据处理逻辑。在 Flink 程序中,通过 `addSink` 方法将数据流发送到自定义 Sink 中进行处理。 需要注意的是,自定义 Sink 函数还可以使用一些钩子方法,如 `open` 和 `close`,可以在其中进行一些初始化和清理操作。 希望这个示例能够帮助你理解如何在 Flink自定义 Sink 函数。如果有任何疑问,请随时提问。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值