一:”Hello RabbitMQ”
下面有一幅图,其中P表示生产者,C表示消费者,红色部分为消息队列
客户端:
package rabbitmq;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
public class Send {
private final static String QUEUE_NAME = "hello";
public static void main(String[] argv) throws Exception {
//创建连接工厂
ConnectionFactory factory = new ConnectionFactory();
//设置连接信息
factory.setHost("1y2812381");
factory.setUsername("wang");
factory.setPassword("wang");
//创建连接
Connection connection = factory.newConnection();
//打开通道
Channel channel = connection.createChannel();
//声明一个消息队列
/*注1:queueDeclare第一个参数表示队列名称、第二个参数为是否持久化(true表示是,队列将在服务器重启时生存)
、第三个参数为是否是独占队列(创建者可以使用的私有队列,断开后自动删除)
、第四个参数为当所有消费者客户端连接断开时是否自动删除队列、第五个参数为队列的其他参数*/
channel.queueDeclare(QUEUE_NAME, false, false, false, null);
String message = "Hello World!";
//消息推送
/*注2:basicPublish第一个参数为交换机名称、第二个参数为队列映射的路由key
、第三个参数为消息的其他属性、第四个参数为发送信息的主体*/
channel.basicPublish("", QUEUE_NAME, null, message.getBytes("UTF-8"));
System.out.println(" [x] Sent '" + message + "'");
//关闭通道,断开连接
channel.close();
connection.close();
}
}
接收端:
import com.rabbitmq.client.*;
import java.io.IOException;
public class Recv {
private final static String QUEUE_NAME = "hello";
public static void main(String[] argv) throws Exception {
// 创建连接工厂
ConnectionFactory factory = new ConnectionFactory();
// 设置连接信息
factory.setHost("1y2812381");
factory.setUsername("wang");
factory.setPassword("wang");
// 创建连接
Connection connection = factory.newConnection();
// 打开通道
Channel channel = connection.createChannel();
// 声明一个消息队列(此队列和发送端的队列信息保持一致,否则会报错(Channel Error))
channel.queueDeclare(QUEUE_NAME, false, false, false, null);
System.out.println(" [*] Waiting for messages. To exit press CTRL+C");
// DefaultConsumer类实现了Consumer接口,通过传入一个频道,
// 告诉服务器我们需要那个频道的消息,如果频道中有消息,就会执行回调函数handleDelivery
Consumer consumer = new DefaultConsumer(channel) {
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties,
byte[] body) throws IOException {
String message = new String(body, "UTF-8");
System.out.println(" [x] Received '" + message + "'");
}
};
// 自动回复队列应答 -- RabbitMQ中的消息确认机制
// 第一个参数是消息队列,第二个参数是手动应答标志如果为true的话,每次生产者只要发送信息就会从内存中删除
// 第三个参数是消费者
channel.basicConsume(QUEUE_NAME, true, consumer);
}
}
二:实现任务分发
工作队列
一个队列的优点就是很容易处理并行化的工作能力,但是如果我们积累了大量的工作,我们就需要更多的工作者来处理,这里就要采用分布机制了。
发送端:
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_queue12";
public static void main(String[] argv) throws Exception {
//创建工厂
ConnectionFactory factory = new ConnectionFactory();
//创建工厂连接信息
factory.setHost("1y2812381");
factory.setUsername("wang");
factory.setPassword("wang");
//创建连接
Connection connection = factory.newConnection();
//创建通道
Channel channel = connection.createChannel();
//创建队列 消息本地持久化
channel.queueDeclare(TASK_QUEUE_NAME, true, false, false, null);
for (int i = 0; i < 10; i++) {
String message = "hello" + i;
channel.basicPublish("", TASK_QUEUE_NAME, MessageProperties.PERSISTENT_TEXT_PLAIN,
message.getBytes("UTF-8"));
System.out.println(" [x] Sent '" + message + "'");
}
channel.close();
connection.close();
}
}
接收端1:
package rabbitmq;
import com.rabbitmq.client.*;
import java.io.IOException;
public class Worker2 {
private static final String TASK_QUEUE_NAME = "task_queue12";
public static void main(String[] argv) throws Exception {
// 创建工厂
ConnectionFactory factory = new ConnectionFactory();
// 创建工厂连接信息
factory.setHost("1y2812381");
factory.setUsername("wang");
factory.setPassword("wang");
// 创建连接
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);
final Consumer consumer = new DefaultConsumer(channel) {
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties,
byte[] body) throws IOException {
String message = new String(body, "UTF-8");
System.out.println(" [x] Received '" + message + "'");
try {
doWork(message);
} finally {
System.out.println(" [x] Done");
//
channel.basicAck(envelope.getDeliveryTag(), false);
}
}
};
//手动消息确认默认打开。在前面的例子中,我们明确地通过设置为true 标志关闭了它们。
//一旦我们完成了一项任务,现在是时候将这个标志设置为false,并且向工作人员发送一个正确的确认。
channel.basicConsume(TASK_QUEUE_NAME, false, consumer);
}
private static void doWork(String task) {
try {
Thread.sleep(1000);
} catch (InterruptedException _ignored) {
Thread.currentThread().interrupt();
}
}
}
接收端2和接收端1代码一样
三:发布/订阅
在上一篇说到的队列都指定了名称,但是现在我们不需要这么做,我们需要所有的日志信息,而不只是其中的一个。如果要做这样的队列,我们需要2件事,一个就是获取一个新的空的队列,这样我就需要创建一个随机名称的队列,最好让服务器帮我们做出选择,第一个就是我们断开用户的队列,应该自动进行删除。ok下面是一副工作图。
交换机有几种类型: direct, topic, headers and fanout.
XCHANGE_TYPE:fanout
//fanout表示分发,所有的消费者得到同样的队列信息
发送端:
package rabbitmq;
import com.rabbitmq.client.BuiltinExchangeType;
import com.rabbitmq.client.ConnectionFactory;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.Channel;
public class EmitLog {
private static final String EXCHANGE_NAME = "logs";
public static void main(String[] argv) throws Exception {
//创建工厂
ConnectionFactory factory = new ConnectionFactory();
factory.setHost("1y2812381");
factory.setUsername("wang");
factory.setPassword("wang");
//新建连接
Connection connection = factory.newConnection();
//新建通道
Channel channel = connection.createChannel();
//fanout表示分发,所有的消费者得到同样的队列信息
//建立交换机 第一个参数交换机名称 ,第二个参数交换机类型
channel.exchangeDeclare(EXCHANGE_NAME, BuiltinExchangeType.FANOUT);
String message = "hello";
//消息推送
channel.basicPublish(EXCHANGE_NAME, "", null, message.getBytes("UTF-8"));
System.out.println(" [x] Sent '" + message + "'");
channel.close();
connection.close();
}
}
接收端:
package rabbitmq;
import com.rabbitmq.client.*;
import java.io.IOException;
public class Worker2 {
private static final String EXCHANGE_NAME = "logsq";
public static void main(String[] argv) throws Exception {
// 创建工厂
ConnectionFactory factory = new ConnectionFactory();
factory.setHost("1y2812381");
factory.setUsername("wang");
factory.setPassword("wang");
// 新建连接
Connection connection = factory.newConnection();
// 新建通道
Channel channel = connection.createChannel();
//交换机信息设置
channel.exchangeDeclare(EXCHANGE_NAME, BuiltinExchangeType.FANOUT);
//系统随机生成对列名
String queueName = channel.queueDeclare().getQueue();
//对列绑定交换机
channel.queueBind(queueName, EXCHANGE_NAME, "");
System.out.println(" [*] Waiting for messages. To exit press CTRL+C");
Consumer consumer = new DefaultConsumer(channel) {
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties,
byte[] body) throws IOException {
String message = new String(body, "UTF-8");
System.out.println(" [x] Received '" + message + "'");
}
};
//队列会自动删除
channel.basicConsume(queueName, true, consumer);
}
}
XCHANGE_TYPE:direct
发送端:
package rabbitmq;
import com.rabbitmq.client.BuiltinExchangeType;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import java.util.Random;
import java.util.UUID;
/**
* 生产者根据routing 分别将信息发送给不同的消费者,如果没有消费者接受,那么消息将丢弃
*/
public class DirectProducer {
// 交换名称
private static final String EXCHANGE_NAME = "ex_direct";
public static void main(String[] args) throws Exception {
// 创建一个频道
ConnectionFactory factory = new ConnectionFactory();
factory.setHost("1y2812381");
factory.setUsername("wang");
factory.setPassword("wang");
Connection connection = factory.newConnection();
Channel channel = connection.createChannel();
// 声明转发器的类型
channel.exchangeDeclare(EXCHANGE_NAME, BuiltinExchangeType.DIRECT);
String message = "123";
// 发布消息至转发器,指定routingkey
channel.basicPublish(EXCHANGE_NAME, "severity", null, message.getBytes());
System.out.println(" [x] Sent '" + message + "'");
channel.close();
}
}
接收端:
package rabbitmq;
import java.io.IOException;
import java.util.Random;
import com.rabbitmq.client.AMQP;
import com.rabbitmq.client.BuiltinExchangeType;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import com.rabbitmq.client.Consumer;
import com.rabbitmq.client.DefaultConsumer;
import com.rabbitmq.client.Envelope;
public class DirectConsumer {
private static final String EXCHANGE_NAME = "ex_direct";
public static void main(String[] args) throws Exception {
// 创建一个频道
ConnectionFactory factory = new ConnectionFactory();
factory.setHost("1y2812381");
factory.setUsername("wang");
factory.setPassword("wang");
Connection connection = factory.newConnection();
Channel channel = connection.createChannel();
// 声明direct类型转发器
channel.exchangeDeclare(EXCHANGE_NAME, BuiltinExchangeType.DIRECT);
String queueName = channel.queueDeclare().getQueue();
// 指定binding_key
channel.queueBind(queueName, EXCHANGE_NAME, "severity");
System.out.println(" [*] Waiting for "+"severity"+" logs. To exit press CTRL+C");
Consumer consumer = new DefaultConsumer(channel){
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties,
byte[] body) throws IOException {
String message = new String(body, "UTF-8");
System.out.println(" [x] Received '" + message + "'");
}
};
channel.basicConsume(queueName, true, consumer);
}
}
Topics
发送端:
package rabbitmq;
import java.util.UUID;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
public class EmitLogTopic
{
private static final String EXCHANGE_NAME = "topic_logs";
public static void main(String[] argv) throws Exception
{
// 创建连接和频道
ConnectionFactory factory = new ConnectionFactory();
factory.setHost("192.168.71.127");
factory.setUsername("wang");
factory.setPassword("wang");
//创建连接
Connection connection = factory.newConnection();
//创建通道
Channel channel = connection.createChannel();
//设置交换机主题类型
channel.exchangeDeclare(EXCHANGE_NAME, "topic");
String[] routing_keys = new String[] { "kernel.info.on", "cron.warning",
"auth.info", "kernel.critical" };
//信息推送
for (String routing_key : routing_keys)
{
String msg = UUID.randomUUID().toString();
channel.basicPublish(EXCHANGE_NAME, routing_key, null, msg
.getBytes());
System.out.println(" [x] Sent routingKey = "+routing_key+" ,msg = " + msg + ".");
}
channel.close();
connection.close();
}
}
接收端1:
package rabbitmq;
import java.io.IOException;
import com.rabbitmq.client.AMQP;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import com.rabbitmq.client.Consumer;
import com.rabbitmq.client.DefaultConsumer;
import com.rabbitmq.client.Envelope;
import com.rabbitmq.client.QueueingConsumer;
public class ReceiveLogsTopicForCritical
{
private static final String EXCHANGE_NAME = "topic_logs";
public static void main(String[] argv) throws Exception
{
// 创建连接和频道
ConnectionFactory factory = new ConnectionFactory();
factory.setHost("192.168.71.127");
factory.setUsername("wang");
factory.setPassword("wang");
Connection connection = factory.newConnection();
Channel channel = connection.createChannel();
// 声明转发器
channel.exchangeDeclare(EXCHANGE_NAME, "topic");
// 随机生成一个队列
String queueName = channel.queueDeclare().getQueue();
//接收所有与kernel相关的消息 * 代表一个单词 #代表一个或多个单词
channel.queueBind(queueName, EXCHANGE_NAME, "*.critical");
System.out.println(" [*] Waiting for critical messages. To exit press CTRL+C");
Consumer consumer = new DefaultConsumer(channel){
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties,
byte[] body) throws IOException {
String message = new String(body, "UTF-8");
System.out.println(" [x] Received *.critical'"+envelope.getRoutingKey() + message + "'");
}
};
channel.basicConsume(queueName, true, consumer);
}
}
接收端2:
package rabbitmq;
import java.io.IOException;
import com.rabbitmq.client.AMQP;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import com.rabbitmq.client.Consumer;
import com.rabbitmq.client.DefaultConsumer;
import com.rabbitmq.client.Envelope;
import com.rabbitmq.client.QueueingConsumer;
public class ReceiveLogsTopicForKernel1
{
private static final String EXCHANGE_NAME = "topic_logs";
public static void main(String[] argv) throws Exception
{
// 创建连接和频道
ConnectionFactory factory = new ConnectionFactory();
factory.setHost("192.168.71.127");
factory.setUsername("wang");
factory.setPassword("wang");
Connection connection = factory.newConnection();
Channel channel = connection.createChannel();
// 声明转发器
channel.exchangeDeclare(EXCHANGE_NAME, "topic");
// 随机生成一个队列
String queueName = channel.queueDeclare().getQueue();
//接收所有与kernel相关的消息 * 代表一个单词 #代表一个或多个单词
channel.queueBind(queueName, EXCHANGE_NAME, "kernel.#");
System.out.println(" [*] Waiting for messages about kernel. To exit press CTRL+C");
Consumer consumer = new DefaultConsumer(channel){
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties,
byte[] body) throws IOException {
String message = new String(body, "UTF-8");
System.out.println(" [x] Received kernel.*'"+envelope.getRoutingKey() + message + "'");
}
};
channel.basicConsume(queueName, true, consumer);
}
}