RabbitMQ(4)Java Client - Hello World-Work Queue

本文介绍了如何使用Java客户端与RabbitMQ消息中间件进行交互,包括简单的Hello World示例和工作队列的实现。通过代码示例展示了如何创建生产者、消费者以及持久化消息。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

RabbitMQ(4)Java Client - Hello World-Work Queue

RabbitMQ is a message broker, accepts and forwards messages.

1. RabbitMQ jargon
Producing - A program that sends messages is a producer.
Queue - A queue is the name for a mailbox. It can store as many messages as you like.
Consuming - A consumer is a program that mostly waits to receive messages.

2. Simple Java "Hello World"
RabbitMQ speaks AMQP, which is an open, general-purpose protocol for messaging.

Test Producer
package com.sillycat.easytalker.rabbitmq.hello;
import java.io.IOException;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;

public class TestProducer {
private final static String QUEUE_NAME = "hello";
private final static String SERVER_HOST = "localhost";
public static void main(String[] args) throws IOException {
ConnectionFactory factory = new ConnectionFactory();
factory.setHost(SERVER_HOST);
Connection connection = factory.newConnection();
Channel channel = connection.createChannel();

channel.queueDeclare(QUEUE_NAME, false, false, false, null);
String message = "Hello World! Woo!2";
channel.basicPublish("", QUEUE_NAME, null, message.getBytes());
System.out.println(" [x] Sent '" + message + "'");
channel.close();
connection.close();
}
}

Test Consumer
package com.sillycat.easytalker.rabbitmq.hello;
import java.io.IOException;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import com.rabbitmq.client.ConsumerCancelledException;
import com.rabbitmq.client.QueueingConsumer;
import com.rabbitmq.client.ShutdownSignalException;

public class TestConsumer {
private final static String QUEUE_NAME = "hello";
private final static String SERVER_HOST = "localhost";
public static void main(String[] args) throws IOException,
ShutdownSignalException, ConsumerCancelledException,
InterruptedException {
ConnectionFactory factory = new ConnectionFactory();
factory.setHost(SERVER_HOST);
Connection connection = factory.newConnection();
Channel channel = connection.createChannel();
channel.queueDeclare(QUEUE_NAME, false, false, false, null);
System.out.println(" [*] Waiting for messages. To exit press CTRL+C");
QueueingConsumer consumer = new QueueingConsumer(channel);
channel.basicConsume(QUEUE_NAME, true, consumer);
while (true) {
QueueingConsumer.Delivery delivery = consumer.nextDelivery();
String message = new String(delivery.getBody());
System.out.println(" [x] Received '" + message + "'");
Thread.sleep(5000);
}
}
}

3. Simple Java Work Queues
We will create a Work Queue that will be used to distribute time-consuming tasks among multiple workers.

Work Queues(aka: Task Queues) is to avoid doing a resource-intensive task immediately and having to wait for it to complete.

This concept is especially useful in web applications where it's impossible to handle a complex task during a short HTTP request window.

My NewTask.java Class is mostly the same as before, but we send a lot of tasks this time.
package com.sillycat.easytalker.rabbitmq.workqueue;

import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import com.rabbitmq.client.MessageProperties;

public class NewTask {

private static final String TASK_QUEUE_NAME = "task_queue";

private final static String SERVER_HOST = "localhost";

public static void main(String[] argv) throws Exception {
ConnectionFactory factory = new ConnectionFactory();
factory.setHost(SERVER_HOST);

Connection connection = factory.newConnection();
Channel channel = connection.createChannel();
channel.queueDeclare(TASK_QUEUE_NAME, true, false, false, null);

String message = "job";
for(int i = 0;i<10;i++){
message = "job" + i;
channel.basicPublish("", TASK_QUEUE_NAME,
MessageProperties.PERSISTENT_TEXT_PLAIN, message.getBytes());
System.out.println(" [x] Sent '" + message + "'");
}
channel.close();
connection.close();
}
}

The worker.java class, we can run 2 instances of this class to see, the log messsage as follow:
[*] Waiting for messages. To exit press CTRL+C
[x] Received 'job0'
[x] Done
[x] Received 'job2'
[x] Done
[x] Received 'job4'
[x] Done
[x] Received 'job6'
[x] Done
[x] Received 'job8'
[x] Done

Another Instance:
[*] Waiting for messages. To exit press CTRL+C
[x] Received 'job1'
[x] Done
[x] Received 'job3'
[x] Done
[x] Received 'job5'
[x] Done
[x] Received 'job7'
[x] Done
[x] Received 'job9'
[x] Done

package com.sillycat.easytalker.rabbitmq.workqueue;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import com.rabbitmq.client.QueueingConsumer;
public class Worker {
private static final String TASK_QUEUE_NAME = "task_queue";
private final static String SERVER_HOST = "localhost";
public static void main(String[] argv) throws Exception {
ConnectionFactory factory = new ConnectionFactory();
factory.setHost(SERVER_HOST);

Connection connection = factory.newConnection();
Channel channel = connection.createChannel();
channel.queueDeclare(TASK_QUEUE_NAME, true, false, false, null);

System.out.println(" [*] Waiting for messages. To exit press CTRL+C");

channel.basicQos(1);

QueueingConsumer consumer = new QueueingConsumer(channel);
channel.basicConsume(TASK_QUEUE_NAME, false, consumer);
while (true) {
QueueingConsumer.Delivery delivery = consumer.nextDelivery();
String message = new String(delivery.getBody());
System.out.println(" [x] Received '" + message + "'");
doWork(message);
System.out.println(" [x] Done");
channel.basicAck(delivery.getEnvelope().getDeliveryTag(), false);
}
}

private static void doWork(String task) throws InterruptedException {
for (char ch : task.toCharArray()) {
if (ch == '.')
Thread.sleep(5000);
}
}
}

Message Acknowledgment
If a worker dies, we'd like the task to be delivered to another worker.
RabbitMQ supports message acknowledgements. An ack is sent back from the consumer to tell RabbitMQ that a particular message has been received, processed and that RabbitMQ is free to delete it. (ack acknowledgement charactor)

If a consumer dies without sending an ack, RabbitMQ will understand that a message wasn't processed fully and will redeliver it to another consumer.

Message acknowledgments are turned on by default. autoAck=true flag will turned them off.
boolean autoAck = false;
channel.basicConsume(TASK_QUEUE_NAME, autoAck, consumer);

Message Durability
We have learned how to make sure that even if the consumer dies, the task isn't lost. But our tasks will still be lost if RabbitMQ server stops.

When RabbitMQ quits or crashes it will forget the queues and messages unless you tell it not to. We need to mark both the queue and messages as durable.
boolean durable = true;
channel.queueDeclare("hello", durable, false, false, null);

Set the message to persistent
channel.basicPublish("", TASK_QUEUE_NAME,
MessageProperties.PERSISTENT_TEXT_PLAIN, message.getBytes());
The persistence guarantees aren't strong, but it's more than enough for our simple task queue. If you need a stronger guarantee you can wrap the publishing code in a transaction.

Fair dispatch
In order to defeat that we can use the basicQos method with the prefetchCount = 1 setting. This tells RabbitMQ not to give more than one message to a worker at a time. Or, in other words, don't dispatch a new message to a worker until it has processed and acknowledged the previous one. Instead, it will dispatch it to the next worker that is not still busy.

int prefetchCount = 1;
channel.basicQos(prefetchCount);

references:
http://www.rabbitmq.com/java-client.html
https://github.com/rabbitmq/rabbitmq-tutorials/tree/master/java
http://www.rabbitmq.com/api-guide.html
http://www.rabbitmq.com/getstarted.html
http://www.rabbitmq.com/tutorials/tutorial-two-java.html
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值