rabbitmq(二):rabbitmq的安装和四种交换机整合springboot

1. AMQP协议

(1)二进制协议
(2)消息模型:核心exchange->message queue之间的绑定关系
在这里插入图片描述
(3)概念:
message 由两部分组成: properties和body,在properties中存放的是对消息的消息的修饰,如优先级、延迟。在body中存放的就是消息内容。
virtual host:一个逻辑隔离的虚拟地址。每个虚拟主机都含有若干个exchange和message queue。
exchange:交换机
bingding:exchange于message之间建立消息连接
router key:路由规则,虚拟机确定他如何路由到特定的队列上。
queue:将消息发给cosumer。
在这里插入图片描述

2.rabbitmq安装

安装参考:https://blog.csdn.net/qq_35688140/article/details/100191976

3. 命令行的操作和管控台操作

基础操作
rabbitmqctl stop_app 关闭应用
rabbitmqctl start_app 开启应用
rabbitmqctl status 节点状态
rabbitmqctl add_user username password 新增用户
rabbitmqctl list_users 列出所有用户
rabbitmqctl delete_users username 删除用户
rabbitmqctl clear_permissions -p vhostpath username 清除用户权限
rabbitmqctl list_user_permissions username 列出用户权限
rabbitmqctl change_password username newpassword 修改密码
rabbitmqctl set_permissions -p vhostpath username ".*" ".* " ".*" 设置用户权限

虚拟主机
rabbitmqctl add_vhost vhostpath 创建虚拟主机
rabbitmqctl delete_vhost vhostpath 删除虚拟主机
rabbitmqctl list_vhosts 列出所有的虚拟主机
rabbitmqctl list_permissions -p vhostpath 列出虚拟主机上所有的权限

队列
rabbitmqctl list_queues 查看所有队列信息
rabbitmqctl -p vhostpath purge_queue blue 清除队列里的消息

高级操作
rabbitmqctl reset 移除所有的数据,再关闭rabbitmq之后执行
rabbitmqctl jion_cluster <cluster_node> [--ram] 组成集群命令
rabbitmqctl cluster_status 查看集群状态
rabbitmqctl change_cluster_node_type disc | ram 修改数据存储方式(磁盘|内存)
rabbitmqctl forget_cluster_node [--offline] 忘记节点(将无法使用的节点忘掉,可以在rabbitmq没有启动时使用该命令修改集群信息)

在这里插入图片描述

4.spring整合rabbitmq

pom.xml

		<dependency>
            <groupId>com.rabbitmq</groupId>
            <artifactId>amqp-client</artifactId>
            <version>3.6.5</version>
        </dependency>

producer

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

public class Procuder {
	public static void main(String[] args) throws Exception {
		//1 创建一个ConnectionFactory, 并进行配置
		ConnectionFactory connectionFactory = new ConnectionFactory();
		connectionFactory.setHost("192.168.48.142");
		connectionFactory.setPort(5672);
		connectionFactory.setVirtualHost("/");
		// 设置
		connectionFactory.setUsername("admin");
		connectionFactory.setPassword("123456");
		
		//2 通过连接工厂创建连接
		Connection connection = connectionFactory.newConnection();
		
		//3 通过connection创建一个Channel
		Channel channel = connection.createChannel();
		
		//4 通过Channel发送数据
		for(int i=0; i < 5; i++){
			String msg = "Hello RabbitMQ!";
			//1 exchange   2 routingKey
            // 如果不指定exchange就变成直连的方式,routingKey就是队列的名称
			channel.basicPublish("", "test001", null, msg.getBytes());
		}

		//5 记得要关闭相关的连接
		channel.close();
		connection.close();
	}
}

consumer

import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import com.rabbitmq.client.Envelope;
import com.rabbitmq.client.QueueingConsumer;
import com.rabbitmq.client.QueueingConsumer.Delivery;

public class Consumer {

	public static void main(String[] args) throws Exception {
		
		//1 创建一个ConnectionFactory, 并进行配置
		ConnectionFactory connectionFactory = new ConnectionFactory();
		connectionFactory.setHost("192.168.48.142");
		connectionFactory.setPort(5672);
		connectionFactory.setVirtualHost("/");
        connectionFactory.setUsername("admin");
        connectionFactory.setPassword("123456");
		
		//2 通过连接工厂创建连接
		Connection connection = connectionFactory.newConnection();
		
		//3 通过connection创建一个Channel
		Channel channel = connection.createChannel();
		
		//4 声明(创建)一个队列
		String queueName = "test001";
		// 参数1:队列名  参数2:设置为true启动以后队列仍可以使用  参数3: 独占队列,只有当ip可以连接该队列  参数4:自动删除
		channel.queueDeclare(queueName, true, false, false, null);
		
		//5 创建消费者
		QueueingConsumer queueingConsumer = new QueueingConsumer(channel);
		
		//6 设置Channel
        // 参数1:需要去消费的队列  参数2:自动签收数据  参数3:消费者
		channel.basicConsume(queueName, true, queueingConsumer);
		
		while(true){
			//7 获取消息
			Delivery delivery = queueingConsumer.nextDelivery();//Delivery是一个封装类,用于获取消息
			String msg = new String(delivery.getBody());
			System.out.println("消费端: " + msg);
			//Envelope envelope = delivery.getEnvelope();
		}
		
	}
}

测试:
在这里插入图片描述

5. 交换机

交换机更具routingkey将消息分发给不同的queue,queue的监听者就可以收到消息。
在这里插入图片描述
durability:是否将消息持久化到磁盘。
auto delete:当exchange上的所有的队列都被删除以后,exchange自动被删除。

5.1 直连:

通过routingkey,将消息发送给与routingkey相同的queuename的队列上。
在这里插入图片描述

5.2 topic交换机

根据routingkey将消息发给不同的queue,exchange中设置了routingkey和queue之间的路由规则。
如图:当路由规则是队列1与usa.#绑定,routingkey是usa.news和usa.weather的消息就会被发给这个队列1。
在这里插入图片描述

5.3 fanout

该交换机因为没有路由规则的匹配,所以速度是最快的。是广播模式发送消息。。

5.4 header

根据消息的header头部进行匹配路由。使用场景较少。

6.springboot实现四种交换机模式

springboot整合rabbitmq

		<!--rabbitmq springboot版本-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-amqp</artifactId>
        </dependency>

application.prperties

########################################################################
# rabbitmq
########################################################################
spring.rabbitmq.host=192.168.48.142
spring.rabbitmq.port=5672
spring.rabbitmq.username=admin
spring.rabbitmq.password=123456
# 虚拟多个rabbitmq默认写法,即使guest也可以访问该目录
spring.rabbitmq.virtual-host=/
#消费者最大连接数量
spring.rabbitmq.listener.simple.concurrency= 10
spring.rabbitmq.listener.simple.max-concurrency= 10
#每次连接取一个线程读写
spring.rabbitmq.listener.simple.prefetch= 1
#消费者启动
spring.rabbitmq.listener.simple.auto-startup=true
#消费者消费数据失败重试
spring.rabbitmq.listener.simple.default-requeue-rejected= true
#重试的配置
spring.rabbitmq.template.retry.enabled=true
spring.rabbitmq.template.retry.max-attempts=3
spring.rabbitmq.template.retry.multiplier=1.0

四种交换机的配置(路由设置):将交换机与队列对应起来

import org.springframework.amqp.core.*;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.HashMap;
import java.util.Map;


@Configuration
public class MQConfig {

    // 直连模式
    public static final String QUEUE_NAME = "queue";
    // 交换机模式
    public static final String TOPIC_QUEUE1 = "topic.queue1";
    public static final String TOPIC_QUEUE2 = "topic.queue2";
    public static final String TOPIC_EXCHANGE = "topicExchage";
    // 广播类型交换机
    public static final String FANOUT_EXCHANGE = "fanoutxchage";
    // header模式
    public static final String HEADER_QUEUE = "header.queue";
    public static final String HEADERS_EXCHANGE = "headersExchage";
    //秒杀
    public static final String QUEUE_Miaosha = "miaosha_Queue";

    /**
     * 直连(direct模式)
     *
     * @return
     */
    @Bean
    public Queue queue() {
        return new Queue(QUEUE_NAME, true); // 消息队列名称为queue,true表示持久化
    }

    /**
     * 交换机模式
     */
    @Bean
    public Queue topicQueue1() {
        return new Queue(MQConfig.TOPIC_QUEUE1, true);
    }

    @Bean
    public Queue topicQueue2() {
        return new Queue(MQConfig.TOPIC_QUEUE2, true);
    }

    @Bean
    public TopicExchange topicExchange() {
        return new TopicExchange(MQConfig.TOPIC_EXCHANGE);
    }

    // 表示路由key是topic.key1的消息,进入交换机绑定到topicQueue1()消息队列上
    @Bean
    public Binding topicBinding1() {
        return BindingBuilder.bind(topicQueue1()).to(topicExchange()).with("topic.key1");
    }

    // 表示路由key是topic.#的消息,进入交换机绑定到topicQueue2()消息队列上(#是占位符,表示0个以上的数据)
    @Bean
    public Binding topicBinding2() {
        return BindingBuilder.bind(topicQueue2()).to(topicExchange()).with("topic.#");
    }

    /**
     * fanout模式:广播
     */
    @Bean
    public FanoutExchange fanoutExchage() {
        return new FanoutExchange(FANOUT_EXCHANGE);
    }

    // topicQueue1和topicQueue2都绑定到了这个广播类型的交换机上
    @Bean
    public Binding FanoutBinding1() {
        return BindingBuilder.bind(topicQueue1()).to(fanoutExchage());
    }

    @Bean
    public Binding FanoutBinding2() {
        return BindingBuilder.bind(topicQueue2()).to(fanoutExchage());
    }

    /**
     * header模式:指定消息体的头部信息,匹配这一头部信息才可以将数据发入到绑定的消息队列上
     */
    @Bean
    public HeadersExchange headersExchage() {
        return new HeadersExchange(HEADERS_EXCHANGE);
    }

    @Bean
    public Queue headerQueue1() {
        return new Queue(HEADER_QUEUE, true);
    }

    // whereAll(map).match() 表示只有满足这个map中的<key,value>出现才会往消息队列中放入数据
    @Bean
    public Binding headerBinding() {
        Map<String, Object> map = new HashMap<String, Object>();
        map.put("header1", "value1");
        map.put("header2", "value2");
        return BindingBuilder.bind(headerQueue1()).to(headersExchage()).whereAll(map).match();
    }
}

接收者

@Service
public class MQReceiver {

    private static Logger logger = LoggerFactory.getLogger(MQReceiver.class);



    /**
     * direct模式
     * @param message
     */
    @RabbitListener(queues = MQConfig.QUEUE_NAME) // 监听消息队列中的消息
    public void receive(String message){
        logger.info("收到消息:"+ message);
    }

    /**
     * 交换机模式,和fanout模式
     * @param message
     */
    @RabbitListener(queues=MQConfig.TOPIC_QUEUE1)
    public void receiveTopic1(String message) {
        logger.info(" topic queue1 message:"+message);
    }

    @RabbitListener(queues=MQConfig.TOPIC_QUEUE2)
    public void receiveTopic2(String message) {
        logger.info(" topic queue2 message:"+message);
    }

    /**
     * hedder模式,因为sender的数据message为byte[],此处与之匹配
     */
    @RabbitListener(queues=MQConfig.HEADER_QUEUE)
    public void receiveHeaderQueue(byte[] message) {
        logger.info(" header  queue message:"+new String(message));
    }

}

发送者

@RunWith(SpringRunner.class)
@SpringBootTest
public class MQSender {

    private static Logger logger = LoggerFactory.getLogger(MQReceiver.class);

    @Autowired
    AmqpTemplate amqpTemplate; // 操作rabbitmq的工具类

    /**
     * direct模式
     * 发送message到rabbitmq
     */
    @Test
    public void send(){
        String message = "直连 ";
        logger.info("发送消息:"+message);
        amqpTemplate.convertAndSend(MQConfig.QUEUE_NAME, message); // 向MQConfig.QUEUE_NAME发送数据message
    }

    /**
     * 交换机模式:向指定的路由发送数据
     */
    @Test
    public void sendTopic() {
        String message = "交换机 ";
		// 向路由topic.key1和topic.key2发送数据
		amqpTemplate.convertAndSend(MQConfig.TOPIC_EXCHANGE, "topic.key1", message+"1");
		amqpTemplate.convertAndSend(MQConfig.TOPIC_EXCHANGE, "topic.key2", message+"2");
	}

    /**
     * fanout模式:广播类型的交换机
     */
    @Test
    public void sendFanout() {
        String message = "广播类型交换机 ";
		amqpTemplate.convertAndSend(MQConfig.FANOUT_EXCHANGE, "", message);
	}

    /**
     * header模式:匹配header头部信息的交换机
     */
    @Test
    public void sendHeader() {

        String message = "head类型交换机 ";
        //给消息体初始化,并设置消息体的头部
        MessageProperties properties = new MessageProperties();
		properties.setHeader("header1", "value1");
		properties.setHeader("header2", "value2");
        Message obj = new Message(message.toString().getBytes(), properties);

        // 发送带头部的message消息体
        amqpTemplate.convertAndSend(MQConfig.HEADERS_EXCHANGE, "", obj);
    }

}

测试:
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值