rabbitmq学习笔记

应用场景

1.任务异步处理
2.应用程序解耦
3.削峰填谷
例子(来源于黑马视频教程):
如订单系统,在下单的时候就会往数据库写数据。但是数据库只能支撑每秒1000左右的并发写入,并发量再高就容易宕机。低峰期的时候并发也就100多个,但是在高峰期时候,并发量会突然激增到5000以上,这个时候数据库肯定卡死了。
消息被MQ保存起来了,然后系统就可以按照自己的消费能力来消费,比如每秒1000个数据,这样慢慢写入数据库,这样就不会卡死数据库了。
但是使用了MQ之后,限制消费消息的速度为1000,但是这样一来,高峰期产生的数据势必会被积压在MQ中,高峰就被“削”掉了。但是因为消息积压,在高峰期过后的一段时间内,消费消息的速度还是会维持在1000QPS,直到消费完积压的消息,这就叫做“填谷

RabbitMq入门

1、amqp协议:
rabbitmq学习笔记_第1张图片
注解:一个virtual Host 相当于一个数据库,不同的应用连接不同的虚拟机
-简单模式
生产者和消费者通过消息队列直连

package rabbitmq;

import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import org.eclipse.emf.ecore.util.EContentAdapter;

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

public class Producer {
     
    public static void main(String[] args) throws IOException, TimeoutException {
     
        // 创建连接工厂
        ConnectionFactory connectionFactory = new ConnectionFactory();
        connectionFactory.setHost("localhost");
        connectionFactory.setVirtualHost("test");
        connectionFactory.setPort(5672);
        connectionFactory.setUsername("guest");
        connectionFactory.setPassword("guest");
        // 创建连接
        Connection connection = connectionFactory.newConnection();
        Channel channel  =connection.createChannel();
        // 通道绑定消息队列
        // 参数1:队列名称 参数2:是否持久化  参数3:是否独占队列,如果独占其他连接连接不上  参数4:消费完毕是否删除队列
        // 参数5:其他参数
        channel.queueDeclare("test",false,false,false,null);
        // 发布消息
        // 参数1:交换机  参数2:队列  参数3:属性  参数4:消息内容
        channel.basicPublish("","test",null,"hello".getBytes());
        channel.close();
        connection.close();
    }
}
package rabbitmq;

import com.rabbitmq.client.*;

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

public class Consumer {
     
    public static void main(String[] args) throws IOException, TimeoutException {
     
        // 创建连接工厂
        ConnectionFactory connectionFactory = new ConnectionFactory();
        connectionFactory.setHost("localhost");
        connectionFactory.setVirtualHost("test");
        connectionFactory.setPort(5672);
        connectionFactory.setUsername("guest");
        connectionFactory.setPassword("guest");
        // 创建连接
        Connection connection = connectionFactory.newConnection();
        Channel channel  =connection.createChannel();
        // 通道绑定消息队列
        // 参数1:队列名称 参数2:是否持久化  参数3:是否独占队列,如果独占其他连接连接不上  参数4:消费完毕是否删除队列
        // 参数5:其他参数
        channel.queueDeclare("test",false,false,false,null);
        // 发布消息
        // 参数1:队列  参数2:是否自动确认消息,实际开发中一般手动确认  参数3:消费回调
        channel.basicConsume("test",true,new DefaultConsumer(channel) {
     
            @Override
            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
     
                System.out.println("收到消息:" + new String(body));
            }
        });
        // 不关闭一直监听队列
//        channel.close();
//        connection.close();
    }
}

// 设置消息持久化
channel.basicPublish("","test", MessageProperties.PERSISTENT_TEXT_PLAIN,"hello".getBytes());

在这里插入图片描述
-工作模式
平均消费,代码同上,只是有多个消费者
rabbitmq学习笔记_第2张图片

 for (int i = 0; i < 3; i++) {
     
            channel.basicPublish("","test", MessageProperties.PERSISTENT_TEXT_PLAIN,"hello".getBytes());
        }

注解:发送三条消息,每个消费者消费一条数据
rabbitmq学习笔记_第3张图片

消息确认机制

在这里插入图片描述
为true:消息自动确认,消息发送过来的时候就确认,如果此时rabbit挂掉则消息丢失。
为fasle:手动确认,业务逻辑执行完毕则确认

 // 设置一次消费一条
        channel.basicQos(1);
        channel.basicConsume("test",true,new DefaultConsumer(channel) {
     
            @Override
            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
     
                System.out.println("收到消息:" + new String(body)); 
                // 参数1:确认消息的tag
                channel.basicAck(envelope.getDeliveryTag(),false);
            }

        });

-扇出模型,广播模型
消息先发送到交换机,交换机发送到队列
rabbitmq学习笔记_第4张图片

package rabbitmq;

import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import com.rabbitmq.client.MessageProperties;
import org.eclipse.emf.ecore.util.EContentAdapter;

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

public class Producer {
     
    public static void main(String[] args) throws IOException, TimeoutException {
     
        // 创建连接工厂
        ConnectionFactory connectionFactory = new ConnectionFactory();
        connectionFactory.setHost("localhost");
        connectionFactory.setVirtualHost("test");
        connectionFactory.setPort(5672);
        connectionFactory.setUsername("guest");
        connectionFactory.setPassword("guest");
        // 创建连接
        Connection connection = connectionFactory.newConnection();
        Channel channel  =connection.createChannel();
        // 参数1:交换机名称   参数2:交换机类类型  fanout 广播
        channel.exchangeDeclare("exchange","fanout");
        channel.queueDeclare("test",false,false,false,null);
        // 发布消息
        // 参数1:交换机  参数2:队列  参数3:属性  参数4:消息内容
        for (int i = 0; i < 3; i++) {
     
            channel.basicPublish("exchange","test", MessageProperties.PERSISTENT_TEXT_PLAIN,"hello".getBytes());
        }
        channel.close();
        connection.close();
    }
}

package rabbitmq;

import com.rabbitmq.client.*;

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

public class Consumer {
     
    public static void main(String[] args) throws IOException, TimeoutException {
     
        // 创建连接工厂
        ConnectionFactory connectionFactory = new ConnectionFactory();
        connectionFactory.setHost("localhost");
        connectionFactory.setVirtualHost("test");
        connectionFactory.setPort(5672);
        connectionFactory.setUsername("guest");
        connectionFactory.setPassword("guest");
        // 创建连接
        Connection connection = connectionFactory.newConnection();
        Channel channel  =connection.createChannel();
        // 通道绑定消息队列
        channel.exchangeDeclare("exchange","fanout");
        // 临时队列
        String q = channel.queueDeclare().getQueue();
        // 绑定交换机
        channel.queueBind(q,"exchange","");
        // 发布消息
        channel.basicQos(1);
        channel.basicConsume(q,true,new DefaultConsumer(channel) {
     
            @Override
            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
     
                System.out.println("收到消息:" + new String(body));
                // 参数1:确认消息的tag
                channel.basicAck(envelope.getDeliveryTag(),false);
            }

        });

        // 不关闭一直监听队列
//        channel.close();
//        connection.close();
    }
}

注解:此种模式多个消费者都能消费到等价的消息,由于测试是用的临时队列消费完毕及删除,所以第二次发送消息的时候不会消费到消息。
-路由模式
rabbitmq学习笔记_第5张图片

发送消息,不同的消费者消费不同的消息

package rabbitmq;

import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import com.rabbitmq.client.MessageProperties;
import org.eclipse.emf.ecore.util.EContentAdapter;

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

public class Producer {
     
    public static void main(String[] args) throws IOException, TimeoutException {
     
        // 创建连接工厂
        ConnectionFactory connectionFactory = new ConnectionFactory();
        connectionFactory.setHost("localhost");
        connectionFactory.setVirtualHost("test");
        connectionFactory.setPort(5672);
        connectionFactory.setUsername("guest");
        connectionFactory.setPassword("guest");
        // 创建连接
        Connection connection = connectionFactory.newConnection();
        Channel channel  =connection.createChannel();
        // 参数1:交换机名称   参数2:交换机类类型  fanout 广播
        channel.exchangeDeclare("rute","direct",true);
        // 发布消息
        // 参数1:交换机  参数2:队列  参数3:属性  参数4:消息内容
        for (int i = 0; i < 3; i++) {
     
            channel.basicPublish("rute","error", MessageProperties.PERSISTENT_TEXT_PLAIN,"hello error".getBytes());
        }
        channel.close();
        connection.close();
    }
}

package rabbitmq;

import com.rabbitmq.client.*;

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

public class Consumer {
     
    public static void main(String[] args) throws IOException, TimeoutException {
     
        // 创建连接工厂
        ConnectionFactory connectionFactory = new ConnectionFactory();
        connectionFactory.setHost("localhost");
        connectionFactory.setVirtualHost("test");
        connectionFactory.setPort(5672);
        connectionFactory.setUsername("guest");
        connectionFactory.setPassword("guest");
        // 创建连接
        Connection connection = connectionFactory.newConnection();
        Channel channel  =connection.createChannel();
        // 通道绑定消息队列
        channel.exchangeDeclare("rute","direct",true);
        // 临时队列
        String q = channel.queueDeclare().getQueue();
        // 绑定交换机
        channel.queueBind(q,"rute","error");
        // 发布消息

        channel.basicConsume(q,true,new DefaultConsumer(channel) {
     
            @Override
            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
     
                System.out.println("收到消息:" + new String(body));
                // 参数1:确认消息的tag
                channel.basicAck(envelope.getDeliveryTag(),false);
            }

        });

        // 不关闭一直监听队列
//        channel.close();
//        connection.close();
    }
}

  // 创建连接
        Connection connection = connectionFactory.newConnection();
Channel channel  =connection.createChannel();
 // 通道绑定消息队列
 channel.exchangeDeclare("rute","direct",true);
 // 临时队列
 String q = channel.queueDeclare().getQueue();
 // 绑定交换机
 channel.queueBind(q,"rute","info");

-动态路由
rabbitmq学习笔记_第6张图片

其本质和direct没有区别,只是路由的关键字变为了通配符
此时队列命名:xxx.xxx.xx以点号分隔

*:匹配一个字符
e;*.user.*  路由关键字为三个单词,第二个为user
#:匹配多个字符
e:login.#   路由关键字以login开头就行了如login.uer.save.info

producer

// 参数1:交换机名称   参数2:交换机类类型  fanout 广播
      channel.exchangeDeclare("topic","topic",true);
      // 发布消息
      // 参数1:交换机  参数2:队列  参数3:属性  参数4:消息内容
      for (int i = 0; i < 3; i++) {
     
          channel.basicPublish("topic","info.error", MessageProperties.PERSISTENT_TEXT_PLAIN,"hello error".getBytes());
      }
      for (int i = 0; i < 3; i++) {
     
          channel.basicPublish("topic","info.save", MessageProperties.PERSISTENT_TEXT_PLAIN,"hello save".getBytes());
      }
      for (int i = 0; i < 3; i++) {
     
          channel.basicPublish("topic","info.save.txt", MessageProperties.PERSISTENT_TEXT_PLAIN,"hello save txt".getBytes());
      }
      channel.close();
      connection.close();

consumer

channel.exchangeDeclare("topic","topic",true);
// 临时队列
String q = channel.queueDeclare().getQueue();
// 绑定交换机
channel.queueBind(q,"topic","info.*");
// 发布消息

channel.basicConsume(q,true,new DefaultConsumer(channel) {
     
  @Override
  public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
     
      System.out.println("收到消息:" + new String(body));
      // 参数1:确认消息的tag
      channel.basicAck(envelope.getDeliveryTag(),false);
  }

});

rabbitmq学习笔记_第7张图片
注解:消费者没有消费info save txt的三条消息,因为路由绑定为info.*匹配两个字符且第一个字符为info。

整合springboot

1、简单模式
// 利用spring boot带的RabbitTemplate 进行操作
producer

@Component
public class Producer implements CommandLineRunner {
     
    @Autowired
    RabbitTemplate rabbitTemplate;
    @Override
    public void run(String... args) throws Exception {
     
        producer();
    }
    public void  producer() {
     
        rabbitTemplate.convertAndSend("hello","hello world");
    }
}

consumer

package springbootra;

import org.springframework.amqp.rabbit.annotation.Queue;
import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;

@Component
@RabbitListener(queuesToDeclare = @Queue("hello"))
public class Consumer {
     
    // 表示收到消息用此方法处理
    @RabbitHandler
    public void consum(String msg){
     
        System.out.println("hello");
        System.out.println(msg);
    }
}

注解:
@RabbitListener:监听队列
queuesToDeclare = @Queue(“hello”):申明队列,对应的参数设置参考下图,注意参数值皆为字符串
rabbitmq学习笔记_第8张图片
2、work模式
provider

@Component
public class Producer implements CommandLineRunner {
     
    @Autowired
    RabbitTemplate rabbitTemplate;
    @Override
    public void run(String... args) throws Exception {
     
        producer();
    }
    public void  producer() {
     
        for (int i = 0; i < 6 ; i++) {
     
            rabbitTemplate.convertAndSend("hello","hello world");
        }

    }
}

consumer

@Component
public class Consumer {
     
    // 表示收到消息用此方法处理
    @RabbitListener(queuesToDeclare = @Queue("hello"))
    @RabbitHandler
    public void consum1(String msg){
     
        System.out.println(msg +"consumer1");
    }
    // 表示收到消息用此方法处理
    @RabbitListener(queuesToDeclare = @Queue("hello"))
    @RabbitHandler
    public void consum2(String msg){
     

        System.out.println(msg + "consumer2");
    }
}

3、广播模式

package springbootra;

import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;

import java.util.Properties;
@Component
public class Producer implements CommandLineRunner {
     
    @Autowired
    RabbitTemplate rabbitTemplate;
    @Override
    public void run(String... args) throws Exception {
     
        producer();
    }
    public void  producer() {
     
        for (int i = 0; i < 6 ; i++) {
     
            rabbitTemplate.convertAndSend("springexchange","","hello world" + i);
        }

    }
}

package springbootra;

import org.springframework.amqp.rabbit.annotation.*;
import org.springframework.stereotype.Component;

@Component
public class Consumer {
     
    @RabbitListener(bindings = {
     
            @QueueBinding(
                    //不设置参数表示临时队列
                    value = @Queue,
                    // 绑定交换机
                    exchange = @Exchange(value = "springexchange", type = "fanout")
            )
    }
    )
    public void consum1(String msg){
     
        System.out.println(msg +"consumer1");
    }
    @RabbitListener(bindings = {
     
            @QueueBinding(
                    //不设置参数表示临时队列
                    value = @Queue,
                    // 绑定交换机
                    exchange = @Exchange(value = "springexchange", type = "fanout")
            )
    }
    )
    public void consum2(String msg){
     

        System.out.println(msg + "consumer2");
    }
}

4.路由模式

package springbootra;

import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;

import java.util.Properties;
@Component
public class Producer implements CommandLineRunner {
     
    @Autowired
    RabbitTemplate rabbitTemplate;
    @Override
    public void run(String... args) throws Exception {
     
        producer();
    }
    public void  producer() {
     
        for (int i = 0; i < 2 ; i++) {
     
            rabbitTemplate.convertAndSend("springexchanged","info","hello world info" );
        }
        for (int i = 0; i < 2 ; i++) {
     
            rabbitTemplate.convertAndSend("springexchanged","error","hello world error" );
        }

    }
}

package springbootra;

import org.springframework.amqp.rabbit.annotation.*;
import org.springframework.stereotype.Component;

@Component
public class Consumer {
     
    @RabbitListener(bindings = {
     
            @QueueBinding(
                    //不设置参数表示临时队列
                    value = @Queue,
                    // 绑定交换机,默认type为direct
                    exchange = @Exchange(value = "springexchanged"),
                    key = {
     "error"}
            )
    }
    )
    public void consum1(String msg){
     
        System.out.println(msg +"  consumer1");
    }
    @RabbitListener(bindings = {
     
            @QueueBinding(
                    //不设置参数表示临时队列
                    value = @Queue,
                    // 绑定交换机,默认type为direct
                    exchange = @Exchange(value = "springexchanged"),
                    key = {
     "info"}
            )
    }
    )
    public void consum2(String msg){
     

        System.out.println(msg + "   consumer2");
    }
}

5、动态路由

  @RabbitListener(bindings = {
     
  @QueueBinding(
          //不设置参数表示临时队列
          value = @Queue,
          // 绑定交换机,默认type为direct
          exchange = @Exchange(name = "springexchanged" ,type = "topic"),
          key = {
     "error.*"}
  )
}
)

注解:代码同direct,不在重复。只需要注意绑定交换机类型即可。

你可能感兴趣的:(消息队列)