Spring Cloud Distributed Messaging-Introduction and Getting Started with Spring Cloud Stream

At present, there are many message broker middleware (hereinafter referred to as message brokers) on the market, such as ActiveMQ RabbitMQ, Kafka, RocketMQ, etc. When using these frameworks, we need to call their APIs to send and receive messages. In this blog, we use RabbitMQ as an example. When using RabbitMq alone, we need to create a RabbitMQ client connection, create a Channel, declare a queue, and then publish messages through the Channel. The code is as follows:

//创建连接工厂
ConnectionFactory factory = new ConnectionFactory();
//指定连接服务地址
factory.setHost("localhost");
//获取RabbitMQ连接
try (Connection connection = factory.newConnection(){
    //创建一个Channel
    Channel channel = connection.createChannel());
    //声明一个队列
    channel.queueDeclare(QUEUE_NAME, false, false, false, null);
    String message = "Hello World!";
    //发布消息
    channel.basicPublish("", QUEUE_NAME, null, message.getBytes());
}

If you want to use Kafka or RocketMQ, you need to modify the code to create Kafka and RocketMQ clients, and get the corresponding connection to publish messages. What Spring Cloud Stream has to do is to create the connection of the message middleware, topic or channel, queue, etc. The creation and receipt of messages are encapsulated so that we only need to pay attention to the business logic and not how the messages are published. The Spring Cloud Stream application is composed of third-party middleware. The communication between applications is completed through the input channel and the output channel, and the connection between the channel and the external agent is achieved through Binder. The following figure shows the basic application structure of Spring Cloud Stream.

The message middleware in the above figure refers to message middleware servers such as RabbitMQ, Kafka, RocketMQ, etc. Binder is a message middleware adapter, and different middleware corresponds to different Binder. The Channel represents the channel, and the channel communicates with the message middleware through a clear Binder. In Spring Cloud Stream, we need to receive and send messages through Channel, and Channel communicates with middleware through Binder. Application Core is the encapsulation of the message mechanism implemented by Stream itself, including partitioning and grouping of publish and subscribe semantics, and has nothing to do with specific message middleware. Then we will introduce the use of Spring Cloud Stream with a simple case. In the process of use, our focus is mainly on Channel and Binder.

The first thing we need to look at is Channel. In Spring Cloud Stream, the annotations @Output and @Input can be used to indicate an output channel and an input channel. Annotations can be passed in a string to represent the channel name. The following source code is the default input and output channel provided by Spring Cloud Stream:

//定义了一个名称为input的输入通道Channel
public interface Sink {
    String INPUT = "input";
    //名称为input的输入通道Channel
    @Input("input")
    SubscribableChannel input();
}
//定义了一个名称为input的输出通道Channel
public interface Source {
    String OUTPUT = "output";
    //名称为output的输出通道Channel
    @Output("output")
    MessageChannel output();
}

When receiving and sending messages, we only need to interact with the input channel and the output channel, without paying attention to how the message is sent and received. We said that the Channel needs to be bound to the Binder. Use @EnableBinding to bind input and output channels in Spring Cloud Stream, and its parameters are Class instances of input or output channels. For example, if we want to bind the default channel, we only need to use the following annotation method:

//用于接收消息
@EnableBinding(Sink.class)
public class SinkReceiver {
}
//用于发送消息
@EnableBinding(Source.class)
public class SinkSender {
}

As in the above code, we use the @EnableBinding annotation to bind the input and output channels, but no logic is implemented. The reception and transmission of any messages in the future only need to interact with the input and output channels. First, let's look at the message sending. The output method is provided in Source to return a MessageChannel instance, which can be used to send messages. The code is as follows:

@EnableBinding(Source.class)
public class SinkSender {
    private static Logger logger = LoggerFactory.getLogger(SinkReceiver.class);
    //注入Source实例
    @Autowired
    private Source source;
    public void sendMessage() {
        //获取MessageChannel实例,并且发送消息到中间件
        source.output().send(MessageBuilder.withPayload("hello").build());
    }
}

After writing the logic for sending messages, we now write the logic for receiving messages. Unlike sending messages, we can directly obtain a Source instance to obtain a channel. To receive messages, we need to bind an input channel with the @StreamListener annotation. For example: @StreamListener(Sink.INPUT) , The following code is an example of receiving a message:

@EnableBinding(Sink.class)
public class SinkReceiver {
    private static Logger logger = LoggerFactory.getLogger(SinkReceiver.class);
    //使用注解绑定一个输入通道
    @StreamListener(Sink.INPUT)
    public void receive(String payload) {
        logger.info("Received: " + payload);
    }
}

After writing the message receiving and sending channel, we need to configure the channel to bind to the binder. The following configuration is to bind the input and output channels to the binder named hello1, and the binder binds the message middleware.

spring:
  cloud:
    stream:
      bindings: #用于绑定通道到binder
        input: #ChannelName 这里是输入通道的名称,如果@Input不指定默认为方法名
          destination: hello #从哪里接收消息,这里指topic或者队列名称,在rabbit中为exchange
          binder: hello1 #绑定到名为hello1的binder
        output: #ChannelName 这里是输出通道的名称,如果@Output不指定默认为方法名
          destination: hello #将消息发送到哪里,这里指topic或者队列名称,在rabbit中为exchange
          binder: hello1 #绑定到名为hello1的binder
      binders: #配置binder
        hello1: #配置名称为hello1的binder
          type: rabbit #binder类型为rabbitMq
          environment: #配置运行环境
            spring:
              rabbitmq:
                host: 127.0.0.1  #地址
                port: 5672        #端口
                username: guest   #用户名
                password: guest   #密码
server:
  port: 8092

After the example is running, we can log in to the RabbitMQ console and we can see that an exchange named hello and a Queue named hello.anonymous.8gUlpsRTQNqThYfM52Krgw have been generated . Compared to our previous structure diagram, perhaps the following diagram can better express the message flow in Spring Cloud Stream, as shown below:

The message sending channel interface Source is used to bind to the external channel. We can define the name of the channel through the annotation @Output. When using this channel to send a message, Spring Cloud Stream will serialize the message, and then send the message to the responding message middleware through the MessageChannel provided by the interface.

The message channel is an abstraction of the message queue, used to store the messages published by the message publisher or the messages to be consumed by the consumers. When sending a message to the message middleware, you need to specify the name of the message queue or topic to be sent. Here, Spring Cloud Stream is abstracted. Developers only need to define the message channel to which message queue the message channel is sent. Configure in the configuration file, such as the configuration file we configured earlier.

Spring Cloud Stream realizes the isolation between the application and the details of the specific message middleware by defining the binder as the middle layer, and exposes a unified message channel to the application, so that the application does not need to consider various message middleware. The docking. When it is necessary to upgrade or change a different message middleware, the application only needs to replace the corresponding binder without modifying any application logic.

When configuring the channel, we can also customize the input type or output message type. In the previous example, we used the string type. In fact, its default type is json. We can use spring.cloud.stream.bindings. <channelName>.content-type configures the transmission type. The following are the types supported by Spring Cloud Stream:

application/json
application/octet-stream
text/plain
application/x-java-object;type=foo.bar.Cat

In this article, we only briefly introduce the use of Spring Cloud Stream. In the next article, we will introduce how Spring Cloud Stream customizes channels and more features of Spring Cloud Stream.

Guess you like

Origin blog.csdn.net/wk19920726/article/details/108339641