rabbitMq入门-第二章

一,基础知识快速恶补

1.了解一下什么是 AMQP:

  • 即Advanced Message Queuing Protocol,一个提供统一消息服务的应用层标准高级消息队列协议,是应用层协议的一个开放标准,为面向消息的中间件设计。基于此协议的客户端与消息中间件可传递消息,并不受客户端/中间件不同产品,不同的开发语言等条件的限制。Erlang中的实现有RabbitMQ等。

2. RabbitMq中的AMQP:

  • 生产者:消息提供者,将消息发送到RabbitMq
  • 消费者:订阅RabbitMq队列中的消息,并把
  • 消息    :   向RabbitMq发送的消息体
  • 交换器: 生产者将消息发布到交换器
  • 队列    :   用于存储消息体  
  • 路由键: 通过指定路由键绑定指定的队列
  • 绑定    :   绑定关系,用于交换器与队列之间的绑定
队列通过路由键绑定到交换器,生产者将消息发布到交换器,交换器根据绑定的路由键将消息路由到特定队列,
然后由订阅这个队列的消费者进行接收。
 

 

 AMQP之间的关系就如上图,基础的东西我们就了解到这里,百度上多的是,想进一步了解可以自己百度一下,接下来我们真枪实弹的干起来。

3.了解RabbitMq四种交换器

  • direct : Rabbitmq的默认交换器,队列的通过路由键一对一绑定
  • fanout : Rabbitmq的消息广播,每一个队列都能收到消息
  • topic :   Rabbitmq根据通配符去将消息发送到指定的队列,例如有三个队列名称分别叫(queue.a.array,queue.a.list,queue.b),现在消费者路由键如果是 queue.# 就代表着要消费以queue开头的队列,还有一个 queue.* 这个只会匹配到点的后一位也就是说只能接受
    queue.b路由键的消息
    
    
  • headers : 和direct类似,我工作中几乎没用过,这个了解即可。

二,RabbitMq四种交换器代码演示

1.准备工作

  • 自行创建一个maven项目或者springboot都行
  • 引入rabbitmq原生客户端
<dependency>
<groupId>com.rabbitmq</groupId>
<artifactId>amqp-client</artifactId>
<version>5.0.0</version>
<scope>compile</scope>
</dependency>

2.编写一个Direct生产者和消费者

 Direct 交换器生产者:

package com.lyh.rebbitcase.mq.exchange.direct;

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

import java.io.IOException;
import java.util.concurrent.TimeoutException;

/**
* Direct 交换器生产者
*/
public class DirectProduct {
public static final String EXCHANGE_NAME = "direct";

public static void main(String[] args) throws IOException, TimeoutException {
//创建连接,连接到RabbitMq
ConnectionFactory connectionFactor = new ConnectionFactory();
connectionFactor.setUsername("lyy");
connectionFactor.setPassword("123456");
//设置一下连接工厂
connectionFactor.setHost("192.168.42.100");
//创建连接
Connection connection = connectionFactor.newConnection();
//创建信道
Channel channel = connection.createChannel();
//在信道中设置交换器,
channel.exchangeDeclare(EXCHANGE_NAME, BuiltinExchangeType.DIRECT);
//声明队列(放到消费者做)
//声明路由建
String[] s={"a","b","c"};
for (int i = 0; i < s.length; i++) {
String key= s[i];
//发送的消息
String message="hello rabbitMq! "+key;
//发布消息
/** 参数解释
* 1.需要发送到那个交换器
* 2.路由建
* 3.属性
* 4.发送的消息
*/
channel.basicPublish(EXCHANGE_NAME,key,null,message.getBytes());
System.out.println("Send: "+key+" message: "+ message);
}
channel.close();
connection.close();
}
}

 Direct 交换器消费者:

package com.lyh.rebbitcase.mq.exchange.direct;

import com.rabbitmq.client.*;

import java.io.IOException;
import java.util.concurrent.TimeoutException;

/**
* 普通消费者
*/
public class NormalConsumer {

public static void main(String[] args) throws IOException, TimeoutException {
//创建连接,连接到RabbitMq
ConnectionFactory connectionFactor = new ConnectionFactory();
connectionFactor.setUsername("lyy");
connectionFactor.setPassword("123456");
//设置一下连接工厂
connectionFactor.setHost("192.168.42.100");
//创建连接
Connection connection = connectionFactor.newConnection();
//创建信道
Channel channel = connection.createChannel();
//在信道中设置交换器,
channel.exchangeDeclare(DirectProduct.EXCHANGE_NAME, BuiltinExchangeType.DIRECT);
//声明队列(放到消费者做)
String queueName = "QUEUE_LYY";
channel.queueDeclare(queueName, false, false, false, null);

//绑定,将队列与路由键绑定
String routingKey = "a";
channel.queueBind(queueName, DirectProduct.EXCHANGE_NAME, routingKey);
System.out.println("等待消息**********************");

//声明一个消费者
final Consumer consumer = new DefaultConsumer(channel) {
/**
*
* @param consumerTag
* @param envelope ;信封
* @param properties 配置信息
* @param body 消息体
* @throws IOException
*/
@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("路由键: " + envelope.getRoutingKey() + " 消费者接受到的消息: " + message);
}
};
//消费者正式开始在一个队列上消费
channel.basicConsume(queueName, true, consumer);
}
}

 Direct 交换器演示结果截图(我的消费者里面只绑定的a路由键,所以我的消费者值消费到了队列中a路由键的消息,这就是所谓的一对一):

 

Direct 交换器总结(一下结论我已经试过了,都是基于我上面普通消费者和生产者代码改造我就不贴出来了):

  •  一个队列多个消费者,消费者会轮询消费这个队列的消息
  • 一个连接多个信道 (每一个信道都能收到所有的消息)
  • 队列与交换器的多重绑定(消费者上绑定了几个路由键,就会消费到几个路由键的消息)

2.编写一个Fanout生产者和消费者

 Fanout交换器生产者(其实也是拿着上面代码进行改造切换成Fanout交换器,大家注意观察细节,看看哪里改变的了):

package com.lyh.rebbitcase.mq.exchange.fanout;

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

import java.io.IOException;
import java.util.concurrent.TimeoutException;

/**
* fanout 交换器生产者 广播 往所有的队列发消息
*/
public class FanoutProduct {
public static final String EXCHANGE_NAME = "fanout";

public static void main(String[] args) throws IOException, TimeoutException {
//创建连接,连接到RabbitMq
ConnectionFactory connectionFactor = new ConnectionFactory();
connectionFactor.setUsername("lyy");
connectionFactor.setPassword("123456");
//设置一下连接工厂
connectionFactor.setHost("192.168.42.100");
//创建连接
Connection connection = connectionFactor.newConnection();
//创建信道
Channel channel = connection.createChannel();
//在信道中设置交换器,
channel.exchangeDeclare(EXCHANGE_NAME, BuiltinExchangeType.FANOUT);
//声明队列(放到消费者做)
//声明路由建
String[] routingKey = {"a", "b", "c"};
for (int i = 0; i < routingKey.length; i++) {
String key = routingKey[i];
//发送的消息
String message = "hello rabbitMq! " + key;
//发布消息
/** 参数解释
* 1.需要发送到那个交换器
* 2.路由建
* 3.属性
* 4.发送的消息
*/
channel.basicPublish(EXCHANGE_NAME, key, null, message.getBytes());
System.out.println("Send: " + key + " message: " + message);
}
channel.close();
connection.close();
}
}

Fanout消费者:

package com.lyh.rebbitcase.mq.exchange.fanout;

import com.rabbitmq.client.*;

import java.io.IOException;
import java.util.concurrent.TimeoutException;

/**
* fanout(广播)消费者,广播到所以队列,忽略路由键绑定
*/
public class Consumer {

public static void main(String[] args) throws IOException, TimeoutException {
//创建连接,连接到RabbitMq
ConnectionFactory connectionFactor = new ConnectionFactory();
connectionFactor.setUsername("lyy");
connectionFactor.setPassword("123456");
//设置一下连接工厂
connectionFactor.setHost("192.168.42.100");
//创建连接
Connection connection = connectionFactor.newConnection();
//创建信道
Channel channel = connection.createChannel();
//在信道中设置交换器,
channel.exchangeDeclare(FanoutProduct.EXCHANGE_NAME, BuiltinExchangeType.FANOUT);
//声明队列(放到消费者做)
String queueName = channel.queueDeclare().getQueue();

//TODO 绑定,将队列与路由键绑定(FANOUT会忽略路由键绑定)
String routingKey = "XXX";
channel.queueBind(queueName, FanoutProduct.EXCHANGE_NAME, routingKey);
System.out.println("等待消息**********************");

//声明一个消费者
final com.rabbitmq.client.Consumer consumer = new DefaultConsumer(channel) {
/**
*
* @param consumerTag
* @param envelope ;信封
* @param properties 配置信息
* @param body 消息体
* @throws IOException
*/
@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("路由键: " + envelope.getRoutingKey() + " 消费者接受到的消息: " + message);
}
};
//消费者正式开始在一个队列上消费
channel.basicConsume(queueName, true, consumer);
}
}

 Fanout交换器演示结果截图(大家这里注意观察,路由键我是随便写了个,大家也可以多开几个消费者和队列,他是会广播到每一个队列的

 

 

 

 

 

 Fanout交换器总结:

  • 会广播到每一个队列中,忽略路由键的作用

3.编写一个Topic生产者和消费者

Topic交换器生产者:

package com.lyh.rebbitcase.mq.exchange.topic;

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

import java.io.IOException;
import java.util.concurrent.TimeoutException;

/**
* topic 交换器生产者 按照路由键的匹配符去发送消息
* 了解重要的两个符号
* 点(.)表示值匹配一个
* 井(#)表示匹配全部
*/
public class TopicProduct {
public static final String EXCHANGE_NAME = "MY_TOPIC";

public static void main(String[] args) throws IOException, TimeoutException {
//创建连接,连接到RabbitMq
ConnectionFactory connectionFactor = new ConnectionFactory();
connectionFactor.setUsername("lyy");
connectionFactor.setPassword("123456");
//设置一下连接工厂
connectionFactor.setHost("192.168.42.100");
//创建连接
Connection connection = connectionFactor.newConnection();
//创建信道
Channel channel = connection.createChannel();
//在信道中设置交换器,
channel.exchangeDeclare(EXCHANGE_NAME, BuiltinExchangeType.TOPIC);
//声明队列(放到消费者做)
//声明路由建
String[] routingKey = {"a.java.spring", "b.java.spring", "c.java.spring"
, "a.cache.redis", "b.cache.redis", "c.cache.redis"
};
for (int i = 0; i < routingKey.length; i++) {
String key = routingKey[i];
//发送的消息
String message = "hello rabbitMq! " + key;
//发布消息
/** 参数解释
* 1.需要发送到那个交换器
* 2.路由建
* 3.属性
* 4.发送的消息
*/
channel.basicPublish(EXCHANGE_NAME, key, null, message.getBytes());
System.out.println("Send: " + key + " message: " + message);
}
channel.close();
connection.close();
}
}

Topic交换器消费者:

package com.lyh.rebbitcase.mq.exchange.topic;

import com.rabbitmq.client.*;

import java.io.IOException;
import java.util.concurrent.TimeoutException;

/**
* Topic 交换器 使用 # 关注所有的消息
*/
public class AConsumer {

public static void main(String[] args) throws IOException, TimeoutException {
//创建连接,连接到RabbitMq
ConnectionFactory connectionFactor = new ConnectionFactory();
connectionFactor.setUsername("lyy");
connectionFactor.setPassword("123456");
//设置一下连接工厂
connectionFactor.setHost("192.168.42.100");
//创建连接
Connection connection = connectionFactor.newConnection();
//创建信道
Channel channel = connection.createChannel();
//在信道中设置交换器,
channel.exchangeDeclare(TopicProduct.EXCHANGE_NAME, BuiltinExchangeType.TOPIC);
//声明队列(放到消费者做)
String queueName = channel.queueDeclare().getQueue();

//TODO Topic交换器 关注a所有的消息
String routingKey = "a.#";
channel.queueBind(queueName, TopicProduct.EXCHANGE_NAME, routingKey);
System.out.println("等待消息**********************");

//声明一个消费者
final Consumer consumer = new DefaultConsumer(channel) {
/**
*
* @param consumerTag
* @param envelope ;信封
* @param properties 配置信息
* @param body 消息体
* @throws IOException
*/
@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("路由键: " + envelope.getRoutingKey() + " 消费者接受到的消息: " + message);
}
};
//消费者正式开始在一个队列上消费
channel.basicConsume(queueName, true, consumer);
}
}

Topic交换器演示截图:

 

 

 大家注意我消费者中的路由键配置:

 

 这里我匹配了有关于a开头所有的消息,这里主要明白通配符 # 和 * 的区别大家可以自己多做做实验就明白了

 

入门到这里其实就结束了,希望大家能有所收获,还有一个 headers 交换器大家了解即可,我自己感觉没啥用处。

下一篇就开始我们rebbitmq的高级特性了。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

posted @ 2021-03-31 20:32  IGru  阅读(65)  评论(0)    收藏  举报