Android application integration RabbitMQ message processing guide

Android application integration RabbitMQ message processing guide

RabbitMQ

RabbitMQ official website direct train —> ✈✈✈✈✈✈

1 Introduction

       Recently, I have been busy with work, and I have n’t updated their blogs for a long time.

       For today’s saturated Internet,如何做到不同系统之间传递信息与通信?In actual projects, multiple terminals such as: ios, android, pc, small programs use to obtain real-time packet messages from RabbitMQ, and then use this Real-time packet messages are used for response processing.

       With the development of Internet technology, the coupling degree between systems is getting higher and higher. In order to achieve decoupling between systems, message middleware emerged at the historic moment. Among them, as an excellent one, RabbitMQ is widely used in asynchronous processing, task queues and other fields due to its ease of use, high reliability, multi-protocol support and other features, becoming the first choice for actual projects. 开源消息中间件

       But for many people, RabbitMQ is still relatively unfamiliar. There are many concepts and no idea how to get started, which has become an obstacle for many people to learn and use RabbitMQ. Next, I will introduce you to RabbitMQ.

2. Introduction to RabbitMQ

2.1. What is RabbitMQ?

       MQ stands for Message Queue. Message Queuing (MQ) is an application-to-application communication method. Applications communicate by reading and writing messages (application-specific data) to and from queues without requiring a dedicated connection to link them. Message passing refers to programs communicating with each other by sending data in messages, rather than by making direct calls to each other, which is typically used for techniques such as remote procedure calls. Queuing refers to applications communicating through queues. The use of queues removes the requirement that receiving and sending applications execute simultaneously. Among the more mature MQ products are IBM WEBSPHERE MQ and so on.

RabbitMQ is采用Erlang语言实现的开源消息队列系统 and is one of the most mainstream message middleware currently.

In layman's terms, RabbitMQ is like a post office, responsible for receiving and forwarding letters.

  • Producers are like mail clients, delivering letters (messages) to the RabbitMQ post office.
  • Consumers are like recipients, picking up and processing letters from the RabbitMQ post office.
  • RabbitMQ ensures that each letter (message) will reach the recipient (consumer) safely and reliably, and it will not lose or duplicate letters.
  • RabbitMQ can distribute copies of the same letter to different recipients (consumers), so that multiple recipients can process the letter in parallel.
  • If the RabbitMQ post office accumulates too many letters and has no time to process them, it will queue the letters and send them first-in-first-out sequentially.
  • RabbitMQ can also set priorities for special letters so that important letters can be processed first.
  • RabbitMQ can distribute letters according to the recipient's processing capabilities, and will not let one recipient process too many letters.

So simply put, RabbitMQ is an intelligent post office system that ensures that every message is sent and processed safely and reliably. It is very suitable for messaging and communication between different systems.

2.2. Features of RabbitMQ

  • Supports multiple message protocols, including STOMP, MQTT, etc.
  • Supports message queue and can cache messages.
  • Support message persistence to prevent message loss.
  • Supports complex routing rules and can implement publish-subscribe, load balancing and other functions.
  • High reliability, supports cluster mode.
  • The management interface is friendly and easy to use.

2.3. Working principle of RabbitMQ

  • The producer (Publisher) generates messages and publishes them to the RabbitMQ server.
  • Consumer (Consumer) pulls messages from the RabbitMQ server and processes them.
  • RabbitMQ acts as a message broker, responsible for receiving, storing and forwarding messages.

2.4. Several important concepts in RabbitMQ

  • Producer: The application that sends the message is Producer. Producer publishes messages to RabbitMQ.
  • Consumer: The application that receives the message is Consumer. Consumer gets messages from RabbitMQ for processing.
  • ConnectionFactory (factory class): It is the factory class used by the RabbitMQ Java client to create connections. It encapsulates all parameter configuration used to create a connection.
  • Exchange (switch): The exchange is used to receive messages sent by the producer and route the messages to the specified queue according to the routing key.
  • Queue (message queue): The message queue is the buffer inside RabbitMQ to store messages. The message sent by the Producer will first be stored in the Queue, and the Consumer will obtain the message from the Queue for processing.
  • Channel: A channel for reading and writing messages. It is a virtual connection established on Connection. In order to achieve concurrency and facilitate business and exception isolation, the best practice is to establish multiple Channels based on a single Connection instead of directly operating based on Connection.
  • Routing Key: When the producer publishes a message to Exchange, it will specify a Routing Key. Exchange decides which queue to route the message to based on this Routing Key.
  • Binding: Binding is the association between Exchange and Queue. Routing keys can be included in bindings.
  • Virtual host (virtual host): RabbitMQ can create multiple virtual hosts for permission management and logical isolation.
  • Message Acknowledgment (Message Acknowledgment): Consumers can enable the message acknowledgment mechanism and send a confirmation receipt to RabbitMQ after receiving and processing the message. RabbitMQ will then remove the message from the Queue. Remove.

3. Integrate RabbitMQ in Android Studio

3.1. Add permissions in Manifest:

<uses-permission android:name="android.permission.INTERNET" />

3.2. Add dependencies under build.gradle(:app):

implementation 'com.rabbitmq:amqp-client:5.19.0'

After waiting patiently for as synchronization to complete, you can use the relevant APIs of RabbitMQ.

4. Establish connection

4.1. Create ConnectionFactory object

This object contains the configuration required to create a connection, such as RabbitMQ host address, port, virtual host, username and password, etc.

ConnectionFactory factory = new ConnectionFactory();
// 连接配置
// factory.setHost(Config.MQ_ADDRESS); // 服务器ip
// factory.setPort(Integer.parseInt(Config.MQ_PORT)); // 端口
// factory.setUsername(Config.MQ_USERNAME); // 用户名
// factory.setPassword(Config.MQ_PASSWORD); // 密码
// factory.setVirtualHost(Config.MQ_VIRTUALHOST);
factory.setUri(url);

4.2. Use ConnectionFactory to create a connection

Call the ConnectionFactorycreateConnection() method to create a connection object.

Connection connection = factory.newConnection();

4.3. Create Channel

Create a channel on the connection for message publishing or consumption.

Channel channel = connection.createChannel();

4.4. Declare queues, switches, etc.

Use channels to declare queues, switches, etc.

4.5. Produce or consume news

Send or receive messages through channels.

4.6. Close the connection

Close the connection and channel after use.

channel.close();
connection.close();

5. Send message

5.1. Create connections and channels

Use a ConnectionFactory to create a connection and then create a channel on the connection.

5.2. Declare queue

If the queue does not exist, the queue needs to be declared in advance.

5.3. Prepare message content

Define the message content body to be sent, which can be a byte array or string, etc.

5.4. Release news

The basicPublish method is called using the channel object, which requires the exchange name, routing key and message content.

5.5. Close resources

The channel and connection can be closed after the sending is completed.

5.6. Case

// 构建消息内容
String message = "Hello World!";

// 发布消息到队列
channel.basicPublish(EXCHANGE_NAME, "routingkey", null, message.getBytes());

// 关闭资源
channel.close();
connection.close();

6. Receive messages

6.1. Create connections and channels

Use a ConnectionFactory to create a connection and then create a channel on the connection.

6.2. Declare queue

If the queue does not exist, you need to declare the queue first.

6.3. Define consumers

Implement the Consumer interface and define message processing logic.

6.4. Listening queue

Use the channel object to call the basicConsume method and listen to the specified queue.

6.5. Receive messages

RabbitMQ will deliver messages to Consumer, and the messages can be obtained and processed in the handleDelivery method.

6.6. Confirm message

After processing is completed, call the basicAck method of the channel to manually confirm the message.

6.7. Close resources

Finally the channel and connection need to be closed.

6.8. Case

channel.basicConsume(QUEUE_NAME, true, consumer); 

public class MyConsumer implements Consumer {
    
    
  public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) {
    
    
    // 获取消息并处理
    String message = new String(body, "UTF-8");
    System.out.println("Received message: " + message);
    
    // 确认消息
    channel.basicAck(envelope.getDeliveryTag(), false);
  }
}

7. Confirmation mechanism

The confirmation mechanism in RabbitMQ is mainly divided into two types:

7.1. Publisher Confirms

This is aone-way confirmation mechanism that allows the producer to know whether the message was received by RabbitMQ.

After enabling confirmation mode on the Channel, all messages will be assigned a unique ID (starting from 1). Once the message is delivered to all matching queues, RabbitMQ will send a confirmation to the producer (containing the unique ID of the message) ), which lets the producer know that the message has been processed.

If messages and queues are durable, the acknowledgment mechanism itself is necessary for message persistence.


In the Java client, the Channel can be set to confirmation mode through the Channel's confirmSelect method:

channel.confirmSelect();

You can then add listeners to listen for confirmed and unacknowledged messages:

channel.addConfirmListener(new ConfirmListener(){
    
    
  // ...
});
7.2. Consumer Acknowledgments

This is atwo-way confirmation mechanism, which not only tells the producer that the message has been delivered, but also tells RabbitMQ that the message has been received by the consumer Received and processed.

After the confirmation mode is turned on, once the message is received by the consumer, it will be removed from the RabbitMQ message buffer. If a consumer fails or exits abnormally while processing a message, the unprocessed message will be redistributed to other consumers by RabbitMQ to ensure that the message will not be lost.

By using the confirmation mechanism correctly, you can not only improve the performance and message processing capabilities of RabbitMQ, but also ensure the integrity of the business process. Therefore, in actual use, the confirmation mechanism is very important.


In the Java client, you can set autoAck=false during basicConsume, and then manually call basicAck to achieve confirmation:

channel.basicConsume(queue, false, consumer); 

consumer.handleDelivery(envelope, properties, body) {
    
    
  //...
  channel.basicAck(envelope.getDeliveryTag(), false); 
}

8. Confirm the theme

RabbitMQ has several common topic types. Choosing which one to use mainly depends on the specific application scenario:

8.1. Direct exchange (default)

Direct switch, completely matching the routing key to distribute messages to the queue. The scenario is that a specified queue needs to be received to receive messages.

8.2、Fanout exchange

A fan-out switch will distribute messages to all bound queues. The scenario is that a message needs to be broadcast.

8.3、Topic exchange

The topic switch matches and distributes messages to the queue according to the rules of the routing key. The scenario is that messages need to be distributed to different queues according to rules.

8.4、Headers exchange

The header switch matches and distributes messages according to the headers attributes of the sent message. The scenario is that routing distribution needs to be carried out based on the message header.

The choice of which theme type to use is mainly based on actual business needs:

  • If you need to send messages directly to a specified queue, use thedirect switch.
  • If you need to broadcast messages to all queues, use thefanout switch.
  • If you need to distribute messages based on rule matching, usetopic switch.
  • If distribution based on message header attributes is required, use theheaders switch.

In the code, just specify the type when declaring the switch, as follows:

channel.exchangeDeclare("myExchange","topic");

9. Usage examples

Typical application scenarios and functions of RabbitMQ in multi-terminal applications such as Android, IOS, and small programs:

9.1. Asynchronous processing

Each end can implement asynchronous processing of tasks through RabbitMQ, avoiding user waiting and improving user experience. For example, after placing an order in the mini program, the order information is sent to the server asynchronously through RabbitMQ.

9.2. Push notification

RabbitMQ can be used to implement mobile push notifications, such as order delivery notifications, etc.

9.3. Data transmission

The mobile terminal and server side can transmit data through RabbitMQ to avoid direct coupling and improve transmission flexibility.

9.4. Load balancing

RabbitMQ can perform load balancing between multiple terminals and servers to prevent excessive server pressure.

9.5. Traffic peak clipping

Use RabbitMQ's message queue to handle request peaks and prevent the server from being overwhelmed instantly.

9.6. Service decoupling

Different ends only rely on RabbitMQ for communication and do not need to pay attention to the technical implementation details of the other party to achieve service decoupling.

9.7. Flexible expansion

RabbitMQ can facilitate the flexible expansion of each terminal and server.

9.8. Offline operation support

The mobile terminal can implement certain offline operations through RabbitMQ, and then synchronize to the server after the network is restored.

Practical applications:

       In my actual Internet of Things project, after the user measures body indicators through a wireless device, the device sends the data to the backend through the network; after the backend parses the data, it sends the data to each end through MQ, and each end through the received information packet Do the appropriate processing.

I useConnectionFactory to establish connections through配置Url when configuration is required to create a connection. Start consuming and listening to the specified queue by startConsumer, and then define a callback interface DeliverCallback to receive information packets. Finally, the data packet is delivered throughEventBus.

Show results

Insert image description here
Insert image description here

Implementation

Insert image description here
![Insert image description here](https://img-blog.csdnimg.cn/473682e32d2a48fabd1efa6bba256e84.png

/**
 * @author 拉莫帅
 * @date 2023/10/24
 * @address
 * @Desc EventBus
 */
public class MessageEvent {
    
    
    private String message;

    public String getMessage() {
    
    
        return message;
    }

    public void setMessage(String message) {
    
    
        this.message = message;
    }
}
/**
 * @author 拉莫帅
 * @date 2023/10/24
 * @address
 * @Desc rabbitMQ
 */
public class RabbitMQUtil {
    
    

    private Connection connection;
    private Channel channel;
    private ConnectionFactory factory;
    private String queueName;

    public RabbitMQUtil(String httpType, String userName, String password, String host, String port, String virtualHost, String exChangeName, String bindingKey) {
    
    
        new Thread(new Runnable() {
    
    
            @Override
            public void run() {
    
    
                if (connection == null) {
    
    
                    // 创建一个连接
                    factory = new ConnectionFactory();
                    try {
    
    
                        StringBuilder builder = new StringBuilder();
                        StringBuilder stringBuilder = builder.append(httpType).append("://").append(userName).append(":").append(password)
                                .append("@").append(host).append(":").append(port).append("/").append(virtualHost);
                        String url = stringBuilder.toString();
                        Log.e("RabbitMQ", "Url " + url);

                        // 连接配置
                        // factory.setHost(Config.MQ_ADDRESS); // 服务器ip
                        // factory.setPort(Integer.parseInt(Config.MQ_PORT)); // 端口
                        // factory.setUsername(Config.MQ_USERNAME); // 用户名
                        // factory.setPassword(Config.MQ_PASSWORD); // 密码
                        // factory.setVirtualHost(Config.MQ_VIRTUALHOST);
                        factory.setUri(url);

                        // 创建一个新的代理连接
                        connection = factory.newConnection();
                        // 使用内部分配的通道号创建一个新通道
                        channel = connection.createChannel();
                        channel.exchangeDeclare(exChangeName, "topic", true); // 声明一个转发器

                        queueName = channel.queueDeclare().getQueue();
                        channel.queueBind(queueName, exChangeName, bindingKey); // 绑定一个到转发器
                        Log.e("Waiting for logs.", "");

                        startConsumer();
                    } catch (URISyntaxException e) {
    
    
                        e.printStackTrace();
                    } catch (NoSuchAlgorithmException e) {
    
    
                        e.printStackTrace();
                    } catch (KeyManagementException e) {
    
    
                        e.printStackTrace();
                    } catch (Exception e) {
    
    
                        e.printStackTrace();
                    }
                }
            }
        }).start();
    }

    /**
     * 开始消费
     */
    public void startConsumer() throws Exception {
    
    
        Log.e("startConsumer", "");

        // 定义回调接口DeliverCallback
        DeliverCallback callback = (consumerTag, message) -> {
    
    
            String result = new String(message.getBody(), "UTF-8");
            Log.e("DeliverCallback >>>", result);

            // 创建一个事件
            MessageEvent event = new MessageEvent();
            event.setMessage(result);

            // 通过EventBus发送事件
            EventBus.getDefault().post(event);
        };

        // 启动基本消费,并传入回调接口
        channel.basicConsume(queueName, true, callback, consumerTag -> {
    
    
        });
    }

    /**
     * 关闭连接
     */
    public void close() throws Exception {
    
    
        channel.close();
        connection.close();
    }
}
public class MainActivity extends AppCompatActivity {
    
    

    private static final String bindingKey = "topic.chain=2.region=3.area=4.pharmacy=5.";

    private RabbitMQUtil rabbitMQUtil;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
    
    
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        initMQ();
    }

    private void initMQ() {
    
    
        if (rabbitMQUtil == null) {
    
    
            rabbitMQUtil = new RabbitMQUtil(Config.MQ_HTTP_TYPE, Config.MQ_USERNAME, Config.MQ_PASSWORD,
                    Config.MQ_ADDRESS, Config.MQ_PORT, Config.MQ_VIRTUALHOST, Config.MQ_EXCHANGE, bindingKey);
        }
    }

    @Override
    public void onStart() {
    
    
        super.onStart();

        EventBus.getDefault().register(this);
    }

    @Override
    public void onStop() {
    
    
        super.onStop();

        EventBus.getDefault().unregister(this);
    }

    // 接收事件
    @Subscribe(threadMode = ThreadMode.MAIN)
    public void onMessage(MessageEvent event) {
    
    
        String message = event.getMessage();
        Log.e("接收MQ +++++++++++++", message);

        // 更新UI
        // ...
    }
    
    @Override
    protected void onDestroy() {
    
    
        super.onDestroy();

        new Thread(new Runnable() {
    
    
            @Override
            public void run() {
    
    
                try {
    
    
                    rabbitMQUtil.close();
                } catch (Exception e) {
    
    
                    e.printStackTrace();
                }
            }
        }).start();
    }
}

10. Summary

RabbitMQ's excellent performance and flexibility allow it to handle everything from simple request-response interactions to complex asynchronous processing scenarios.

It can be used not only for asynchronous decoupling between systems, but also for decoupling different components within an application. It is very suitable for data exchange and integration between distributed systems, and has become one of the important components of enterprise-level distributed architecture.

In general, RabbitMQ, as an easy-to-use, stable, and powerful messaging middleware,can provide highly available, scalable, and low-latency messaging services a>, widely used in actual projects. And it occupies a very important position in the current technology stack and is one of the skills that must be mastered.

Guess you like

Origin blog.csdn.net/chen_md/article/details/134133260