RabbitMQ_1.0

RabbitMQ_1.0

在这里插入图片描述

MQ概述

MQ(message Queue)消息队列,即传输过程中保存消息的容器。一般用于分布式系统之间进行通信。

分布式系统通信方式:RPC(远程调用)和第三方完成间接通信(MQ)

  • MQ优势:应用解耦、异步提速、削峰填谷(中间件来承载请求,一次能处理请求的峰值变高了,系统处理请求速度是不变的)
  • 劣势:系统可用性降低(MQ坏掉了)、复杂度提高(要处理消息传递的顺序、丢失情况)、一致性问题(保证消息处理的一致 不能B成功了 C失败了)

什么时候用MQ?

  1. 生产者不需要从消费者那边得到反馈。(消费者不用给生产者数据,影响接下来的操作)
  2. 容许短暂的不一致性(数据处理不同步,MQ告诉用户系统已经处理好了 但其实MQ之后才将消息给订单系统去处理)
  3. 利大于弊(毕竟管理MQ也要成本)

RabbitMQ

AMQP

Advanced Message Queuing Protocol (高级消息队列协议),网络协议的一种,是应用层协议的一个开放标准。

JMS

java消息服务应用程序接口(可以理解为JDBC面向数据库通信,JMS面向消息队列通信)


简单模式

D:\学习总结\后端进阶\pic\20200823183327801.png

引入依赖
<dependencies>
    <!--rabbitmq java客户端-->
    <dependency>
        <groupId>com.rabbitmq</groupId>
        <artifactId>amqp-client</artifactId>
        <version>5.6.0</version>
    </dependency>
</dependencies>

<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>3.8.0</version>
            <configuration>
                <source>1.8</source>
                <target>1.8</target>
            </configuration>
        </plugin>
    </plugins>
</build>

生产者

public class Producer_HelloWorld {
    public final static String QUENE_NAME="hello_world";
    public static void main(String[] args) throws IOException, TimeoutException {

        //创建连接工厂
        ConnectionFactory factory = new ConnectionFactory();
        //设置参数
        factory.setHost("127.0.0.1");
        factory.setPort(5672);
        factory.setVirtualHost("/lxw");
        factory.setUsername("lxw");
        factory.setPassword("lxw");
        //创建连接Connection
        Connection connection = factory.newConnection();
        //创建Channel
        Channel channel = connection.createChannel();
        /*
        创建队列Queue
        queueDeclare(String queue, boolean durable, boolean exclusive, boolean autoDelete, Map<String, Object> arguments)
        参数:
            1.queue:队列名称
            2.durable:是否持久化,当MQ重启之后,还存在
            3.exclusive:
                是否独占,只能有一个消费者监听队列
                当connection关闭时,是否删除队列
            4.outDelete:是否自动删除(没有consumer时)
            5.arguments:参数
            如果有队列则不创建,没有就创建
         */
        channel.queueDeclare(QUENE_NAME,true,false,false,null);
        /*
        发送消息
        basicPublish(String exchange, String routingKey, BasicProperties props, byte[] body)
        参数:
            1.exchange:交换机名称。简单模式下使用默认""
            2.routingKey:路由名称
            3.props:配置信息
            4.body:发送消息数据
         */
        String body="Hello RabbitMQ!";
        channel.basicPublish("", QUENE_NAME, null, body.getBytes());
        //释放资源
        channel.close();
        connection.close();
    }
}

消费者

public class Consumer_HelloWorld {
    public final static String QUEUE_NAME="hello_world";
    public static void main(String[] args) throws IOException, TimeoutException {
        //1.创建连接工厂
        ConnectionFactory factory = new ConnectionFactory();
        //2. 设置IP
        factory.setHost("localhost");
        factory.setPort(5672);
        factory.setVirtualHost("/lxw");
        factory.setUsername("lxw");
        factory.setPassword("lxw");
        //3. 创建连接 Connection
        Connection connection = factory.newConnection();
        //4. 创建Channel
        Channel channel = connection.createChannel();
        channel.queueDeclare(QUEUE_NAME,true,false,false,null);

        // 6.定义队列的消费者,并设置消息处理
        Consumer consumer = new DefaultConsumer(channel){
            /**
             * @param consumerTag 消息者标签,在channel.basicConsume时候可以指定
             * @param envelope 消息包的内容,可从中获取消息id,消息routingKey,交换机,消息和重传标志(收到消息失败后是否需要重新发送)
             * @param properties 属性信息
             * @param body 消息
             */
            @Override
            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
                String msg=new String(body);
                System.out.println("接受到消息:"+msg);
            }

        };

        /**
         * 7.监听队列
         * basicConsume(String queue, boolean autoAck, Consumer callback)
         * queue: 队列名称
         * autoAck:设置为true为表示消息接收到自动向mq回复接收到了,mq接收到回复会删除消息
         * callback 消息接收到后回调
         */
        channel.basicConsume(QUEUE_NAME,true,consumer);

        //不关闭资源,消费者应该一直监听消息
    }
}

工作模式

work queue模式

在这里插入图片描述
在一个队列中,多个消费者共同消费同一个队列中的消息,一个消息只能被一个消费者获取。多个消费者存在竞争关系。

生产者
for(int i=0;i<10;i++){
    String body=i+"Hello RabbitMQ!";
    channel.basicPublish("", QUEUE_NAME, null, body.getBytes());
}
消费者(Consumer_WorkQueues1  和Consumer_WorkQueues2)
/*
	执行两个消费者,监听统一队列 接着执行生产者
	消费者1:
        接受到消息:0Hello RabbitMQ!
        接受到消息:2Hello RabbitMQ!
        接受到消息:4Hello RabbitMQ!
        接受到消息:6Hello RabbitMQ!
        接受到消息:8Hello RabbitMQ!
    消费者2:
    	接受到消息:1Hello RabbitMQ!
        接受到消息:3Hello RabbitMQ!
        接受到消息:5Hello RabbitMQ!
        接受到消息:7Hello RabbitMQ!
        接受到消息:9Hello RabbitMQ!
*/


Pub/Sub订阅模式(Fanout)

在这里插入图片描述

相比于之前的模式,多了一个Exchange角色(交换机),生产者P的消息不再直接发送到队列中,而是优先发给交换机X。

交换机:接收生产者发送的消息。处理消息(递交给某个特别队列,递交给所有队列,丢弃消息)。这里要提一点:交换机只负责转发消息,它不能存储消息。如果没有任何队列和交换机绑定或者没有符合路由规则的队列,消息将会丢失。

交换机类型

  • Fanout:广播,将消息交给所有绑定到交换机的队列
  • Direct:定向,把消息交给符合指定routing key的队列
  • Topic:通配符,把消息交给符合routing pattern的队列
/*
    创建交换机
    String exchange, BuiltinExchangeType type, boolean durable, boolean autoDelete, boolean internal, Map<String, Object> arguments
    参数:
        1.exchange:交换机名称
        2.type:交换机类型
        3.durable:是否持久化
        4.autoDelete:自动删除
        5.internal:内部使用,一般是false
        6.arg:参数
 */
    String exchangeName="test_fanout";
    channel.exchangeDeclare(exchangeName, BuiltinExchangeType.FANOUT,true,false,false,null);
    //创建队列
    String queue1Name="test_fanout_queue1";
    String queue2Name="test_fanout_queue2";
    channel.queueDeclare(queue1Name,true,false,false,null);
    channel.queueDeclare(queue2Name,true,false,false,null);
    //绑定队列和交换机
    channel.queueBind(queue1Name,exchangeName,"");//这里的空字符串是routingkey
    channel.queueBind(queue2Name,exchangeName,"");

    String body="日志信息:张三调用了findAll方法";
    //发送消息
    channel.basicPublish(exchangeName,"",null,body.getBytes());

Routing路由模式(direct)

在这里插入图片描述

在路由模式中,添加了一个功能 (只能订阅一部分消息)。不同的消息被不同的队列消费。 队列与交换机的绑定,不能是任意绑定了,而是要指定一个 RoutingKey(路由key),消息会转发给符合routingkey的队列。

和Fanout模式区别不大,就是多了一个RoutingKey用来限定交换机和队列的绑定


Topics通配符模式

Direct相比,都是可以根据RoutingKey把消息路由到不同的队列。只不过Topic类型Exchange可以让队列在绑定Routing key 的时候使用通配符,更加灵活。

Routingkey 一般都是有一个或多个单词组成,多个单词之间以”.”分割,例如: goods.error

通配符规则

#:匹配一个或多个词

*:匹配不多不少恰好1个词


SpringBoot整合RabbitMQ

springboot-producer
//1.引入依赖 
<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-amqp</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
    </dependency>
</dependencies>
//2.编写配置信息
application.yml
# 配置RabbitMQ的基本信息
spring:
  rabbitmq:
    host: localhost
    port: 5672
    username: guest
    password: guest
    virtual-host: /
//3.编写配置类
@Configuration
public class RabbitMQConfig {
    public static final String EXCHANGE_NAME="boot_topic_exchange";
    public static final String QUEUE_NAME="boot_queue";

    //交换机
    @Bean("bootExchange")
    public Exchange bootExchange(){
        return ExchangeBuilder.topicExchange(EXCHANGE_NAME).durable(true).build();
    }
    //Queue 队列
    @Bean("bootQueue")
    public Queue bootQueue(){
        return QueueBuilder.durable(QUEUE_NAME).build();
    }
    //队列和交换机绑定关系
    @Bean
    public Binding bindQueueExchange(@Qualifier("bootQueue") Queue queue,@Qualifier("bootExchange") Exchange exchange){
        return BindingBuilder.bind(queue).to(exchange).with("boot.#").noargs();
    }

}
//3.注入RabbitTemplate 发送消息
@SpringBootTest
@RunWith(SpringRunner.class)
public class ProducerTest {
    //注入RabbitTemplate
    @Autowired
    private RabbitTemplate rabbitTemplate;
    @Test
    public void testSend(){
  rabbitTemplate.convertAndSend(RabbitMQConfig.EXCHANGE_NAME,"boot.hh","hello rabbitMQ~");
    }

}
springboot-consumer
//坐标(依赖)  配置文件一样不再赘述
@Component
public class RabbitMQListener {
    @RabbitListener(queues = "boot_queue")
    public void ListenerQueue(Message message){
        System.out.println(new String(message.getBody()));
    }
}

小结

除此之外,RabbitMQ还有一些高级特性、应用问题以及集群的搭建需要去了解,将在之后学习并总结出知识点来。"流水不腐,户枢不蠹"谨此以自律。

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值