rabbitMQ基础详解

  • rabbitmq官网
  • 作用
    • 应用解耦
      • 使用MQ后,消费的生产方和消费方不需要进行直连,而是通过MQ连接,那么生产方与消费方之间就没有直接的耦合关系,所以可以降低耦合
    • 异步调用
      • 一个业务需要调用多个方法去实现,而某些方法不需要即时返回结果,那么这些方法就可以使用异步调用去实现。
    • 巅峰填谷
      • 订单系统在下单时,需要向数据库写入消息,同一时间写入操作过多时,就会对数据库造成瞬间压力过大,有可能导致数据库宕机。
        可以使用MQ来存储消息,订单系统监听消费,把消息在单位时间内一定数量【数据库写入能够承受的数量】进行消费,分多次把数据写入数据库,只要保证最终数据能够写入到数据库即可

    • rabbitmq的六种模式
      • 简单模式
      • work模式
      • Publish/Subscribe发布与订阅模式
      • Routing路由模式
      • Topics主题模式
      • RPC远程调用模式(远程调用,不太算MQ;暂不作介绍)
    • rabbitmq的入门
      • 依赖
        • <dependency>
          	<groupId>com.rabbitmq</groupId>
          	<artifactId>amqp-client</artifactId>
          	<version>5.6.0</version>
          </dependency>
      • 编写生产者
        • public class Producer_HelloWorld {
              public static void main(String[] args) throws IOException, TimeoutException {
          
                  //1.创建连接工厂
                  ConnectionFactory factory = new ConnectionFactory();
                  //2. 设置参数
                  factory.setHost("172.16.98.133");//ip  默认值 localhost
                  factory.setPort(5672); //端口  默认值 5672
                  factory.setVirtualHost("/itcast");//虚拟机 默认值/
                  factory.setUsername("heima");//用户名 默认 guest
                  factory.setPassword("heima");//密码 默认值 guest
                  //3. 创建连接 Connection
                  Connection connection = factory.newConnection();
                  //4. 创建Channel
                  Channel channel = connection.createChannel();
                  //5. 创建队列Queue
                  /*
                  queueDeclare(String queue, boolean durable, boolean exclusive, boolean autoDelete, Map<String, Object> arguments)
                  参数:
                      1. queue:队列名称
                      2. durable:是否持久化,当mq重启之后,还在
                      3. exclusive:
                          * 是否独占。只能有一个消费者监听这队列
                          * 当Connection关闭时,是否删除队列
                          *
                      4. autoDelete:是否自动删除。当没有Consumer时,自动删除掉
                      5. arguments:参数。
          
                   */
                  //如果没有一个名字叫hello_world的队列,则会创建该队列,如果有则不会创建
                  channel.queueDeclare("hello_world",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~~~";
          
                  //6. 发送消息
                  channel.basicPublish("","hello_world",null,body.getBytes());
          
          
                  //7.释放资源
                channel.close();
                connection.close();
          
              }
          }
      • 创建消费者工程
        • 引入依赖
          • <dependency>
            	<groupId>com.rabbitmq</groupId>
            	<artifactId>amqp-client</artifactId>
            	<version>5.6.0</version>
            </dependency>
        • 编写消费者
          • public class Consumer_HelloWorld {
                public static void main(String[] args) throws IOException, TimeoutException {
            
                    //1.创建连接工厂
                    ConnectionFactory factory = new ConnectionFactory();
                    //2. 设置参数
                    factory.setHost("172.16.98.133");//ip  默认值 localhost
                    factory.setPort(5672); //端口  默认值 5672
                    factory.setVirtualHost("/itcast");//虚拟机 默认值/
                    factory.setUsername("heima");//用户名 默认 guest
                    factory.setPassword("heima");//密码 默认值 guest
                    //3. 创建连接 Connection
                    Connection connection = factory.newConnection();
                    //4. 创建Channel
                    Channel channel = connection.createChannel();
                    //5. 创建队列Queue
                    /*
                    queueDeclare(String queue, boolean durable, boolean exclusive, boolean autoDelete, Map<String, Object> arguments)
                    参数:
                        1. queue:队列名称
                        2. durable:是否持久化,当mq重启之后,还在
                        3. exclusive:
                            * 是否独占。只能有一个消费者监听这队列
                            * 当Connection关闭时,是否删除队列
                            *
                        4. autoDelete:是否自动删除。当没有Consumer时,自动删除掉
                        5. arguments:参数。
            
                     */
                    //如果没有一个名字叫hello_world的队列,则会创建该队列,如果有则不会创建
                    channel.queueDeclare("hello_world",true,false,false,null);
            
                    /*
                    basicConsume(String queue, boolean autoAck, Consumer callback)
                    参数:
                        1. queue:队列名称
                        2. autoAck:是否自动确认
                        3. callback:回调对象
            
                     */
                    // 接收消息
                    Consumer consumer = new DefaultConsumer(channel){
                        /*
                            回调方法,当收到消息后,会自动执行该方法
            
                            1. consumerTag:标识
                            2. envelope:获取一些信息,交换机,路由key...
                            3. properties:配置信息
                            4. body:数据
            
                         */
                        @Override
                        public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
                            System.out.println("consumerTag:"+consumerTag);
                            System.out.println("Exchange:"+envelope.getExchange());
                            System.out.println("RoutingKey:"+envelope.getRoutingKey());
                            System.out.println("properties:"+properties);
                            System.out.println("body:"+new String(body));
                        }
                    };
                    channel.basicConsume("hello_world",true,consumer);
            
            
                    //关闭资源?不要
            
                }
            }
      • 工作队列模式
        • 多个消费端共同消费同一个队列中的消息,消费者之间是竞争关系
          • 2020-03-18_221626
        • 实现
          • 生产者
            • public class Producer_WorkQueues {
                  public static void main(String[] args) throws IOException, TimeoutException {
              
                      //1.创建连接工厂
                      ConnectionFactory factory = new ConnectionFactory();
                      //2. 设置参数
                      factory.setHost("172.16.98.133");//ip  默认值 localhost
                      factory.setPort(5672); //端口  默认值 5672
                      factory.setVirtualHost("/itcast");//虚拟机 默认值/
                      factory.setUsername("heima");//用户名 默认 guest
                      factory.setPassword("heima");//密码 默认值 guest
                      //3. 创建连接 Connection
                      Connection connection = factory.newConnection();
                      //4. 创建Channel
                      Channel channel = connection.createChannel();
                      //5. 创建队列Queue
                      /*
                      queueDeclare(String queue, boolean durable, boolean exclusive, boolean autoDelete, Map<String, Object> arguments)
                      参数:
                          1. queue:队列名称
                          2. durable:是否持久化,当mq重启之后,还在
                          3. exclusive:
                              * 是否独占。只能有一个消费者监听这队列
                              * 当Connection关闭时,是否删除队列
                              *
                          4. autoDelete:是否自动删除。当没有Consumer时,自动删除掉
                          5. arguments:参数。
              
                       */
                      //如果没有一个名字叫hello_world的队列,则会创建该队列,如果有则不会创建
                      channel.queueDeclare("work_queues",true,false,false,null);
                      /*
                      basicPublish(String exchange, String routingKey, BasicProperties props, byte[] body)
                      参数:
                          1. exchange:交换机名称。简单模式下交换机会使用默认的 ""
                          2. routingKey:路由名称
                          3. props:配置信息
                          4. body:发送消息数据
              
                       */
                      for (int i = 1; i <= 10; i++) {
                          String body = i+"hello rabbitmq~~~";
              
                          //6. 发送消息
                          channel.basicPublish("","work_queues",null,body.getBytes());
                      }
              
              
              
                      //7.释放资源
                    channel.close();
                    connection.close();
              
                  }
              }
          • 消费者
            • public class Consumer_WorkQueues1 {
                  public static void main(String[] args) throws IOException, TimeoutException {
              
                      //1.创建连接工厂
                      ConnectionFactory factory = new ConnectionFactory();
                      //2. 设置参数
                      factory.setHost("172.16.98.133");//ip  默认值 localhost
                      factory.setPort(5672); //端口  默认值 5672
                      factory.setVirtualHost("/itcast");//虚拟机 默认值/
                      factory.setUsername("heima");//用户名 默认 guest
                      factory.setPassword("heima");//密码 默认值 guest
                      //3. 创建连接 Connection
                      Connection connection = factory.newConnection();
                      //4. 创建Channel
                      Channel channel = connection.createChannel();
                      //5. 创建队列Queue
                      /*
                      queueDeclare(String queue, boolean durable, boolean exclusive, boolean autoDelete, Map<String, Object> arguments)
                      参数:
                          1. queue:队列名称
                          2. durable:是否持久化,当mq重启之后,还在
                          3. exclusive:
                              * 是否独占。只能有一个消费者监听这队列
                              * 当Connection关闭时,是否删除队列
                              *
                          4. autoDelete:是否自动删除。当没有Consumer时,自动删除掉
                          5. arguments:参数。
              
                       */
                      //如果没有一个名字叫hello_world的队列,则会创建该队列,如果有则不会创建
                      channel.queueDeclare("work_queues",true,false,false,null);
              
                      /*
                      basicConsume(String queue, boolean autoAck, Consumer callback)
                      参数:
                          1. queue:队列名称
                          2. autoAck:是否自动确认
                          3. callback:回调对象
              
                       */
                      // 接收消息
                      Consumer consumer = new DefaultConsumer(channel){
                          /*
                              回调方法,当收到消息后,会自动执行该方法
              
                              1. consumerTag:标识
                              2. envelope:获取一些信息,交换机,路由key...
                              3. properties:配置信息
                              4. body:数据
              
                           */
                          @Override
                          public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
                            /*  System.out.println("consumerTag:"+consumerTag);
                              System.out.println("Exchange:"+envelope.getExchange());
                              System.out.println("RoutingKey:"+envelope.getRoutingKey());
                              System.out.println("properties:"+properties);*/
                              System.out.println("body:"+new String(body));
                          }
                      };
                      channel.basicConsume("work_queues",true,consumer);
              
              
                      //关闭资源?不要
              
                  }
              }
      • 发布订阅模式
        • 2020-03-18_222153
        • 生产者将消息发给broker,由交换机将消息转发到绑定此交换机的每个队列,每个绑定交换机的队列都将接收到消息
        • 生产者
          • public class Producer_PubSub {
                public static void main(String[] args) throws IOException, TimeoutException {
            
                    //1.创建连接工厂
                    ConnectionFactory factory = new ConnectionFactory();
                    //2. 设置参数
                    factory.setHost("172.16.98.133");//ip  默认值 localhost
                    factory.setPort(5672); //端口  默认值 5672
                    factory.setVirtualHost("/itcast");//虚拟机 默认值/
                    factory.setUsername("heima");//用户名 默认 guest
                    factory.setPassword("heima");//密码 默认值 guest
                    //3. 创建连接 Connection
                    Connection connection = factory.newConnection();
                    //4. 创建Channel
                    Channel channel = connection.createChannel();
                   /*
            
                   exchangeDeclare(String exchange, BuiltinExchangeType type, boolean durable, boolean autoDelete, boolean internal, Map<String, Object> arguments)
                   参数:
                    1. exchange:交换机名称
                    2. type:交换机类型
                        DIRECT("direct"),:定向
                        FANOUT("fanout"),:扇形(广播),发送消息到每一个与之绑定队列。
                        TOPIC("topic"),通配符的方式
                        HEADERS("headers");参数匹配
            
                    3. durable:是否持久化
                    4. autoDelete:自动删除
                    5. internal:内部使用。 一般false
                    6. arguments:参数
                    */
            
                   String exchangeName = "test_fanout";
                    //5. 创建交换机
                    channel.exchangeDeclare(exchangeName, BuiltinExchangeType.FANOUT,true,false,false,null);
                    //6. 创建队列
                    String queue1Name = "test_fanout_queue1";
                    String queue2Name = "test_fanout_queue2";
                    channel.queueDeclare(queue1Name,true,false,false,null);
                    channel.queueDeclare(queue2Name,true,false,false,null);
                    //7. 绑定队列和交换机
                    /*
                    queueBind(String queue, String exchange, String routingKey)
                    参数:
                        1. queue:队列名称
                        2. exchange:交换机名称
                        3. routingKey:路由键,绑定规则
                            如果交换机的类型为fanout ,routingKey设置为""
                     */
                    channel.queueBind(queue1Name,exchangeName,"");
                    channel.queueBind(queue2Name,exchangeName,"");
            
                    String body = "日志信息:张三调用了findAll方法...日志级别:info...";
                    //8. 发送消息
                    channel.basicPublish(exchangeName,"",null,body.getBytes());
            
                    //9. 释放资源
                    channel.close();
                    connection.close();
            
                }
            }
        • 消费者
          • public class Consumer_PubSub1 {
                public static void main(String[] args) throws IOException, TimeoutException {
            
                    //1.创建连接工厂
                    ConnectionFactory factory = new ConnectionFactory();
                    //2. 设置参数
                    factory.setHost("172.16.98.133");//ip  默认值 localhost
                    factory.setPort(5672); //端口  默认值 5672
                    factory.setVirtualHost("/itcast");//虚拟机 默认值/
                    factory.setUsername("heima");//用户名 默认 guest
                    factory.setPassword("heima");//密码 默认值 guest
                    //3. 创建连接 Connection
                    Connection connection = factory.newConnection();
                    //4. 创建Channel
                    Channel channel = connection.createChannel();
            
            
                    String queue1Name = "test_fanout_queue1";
                    String queue2Name = "test_fanout_queue2";
            
            
                    /*
                    basicConsume(String queue, boolean autoAck, Consumer callback)
                    参数:
                        1. queue:队列名称
                        2. autoAck:是否自动确认
                        3. callback:回调对象
            
                     */
                    // 接收消息
                    Consumer consumer = new DefaultConsumer(channel){
                        /*
                            回调方法,当收到消息后,会自动执行该方法
            
                            1. consumerTag:标识
                            2. envelope:获取一些信息,交换机,路由key...
                            3. properties:配置信息
                            4. body:数据
            
                         */
                        @Override
                        public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
                          /*  System.out.println("consumerTag:"+consumerTag);
                            System.out.println("Exchange:"+envelope.getExchange());
                            System.out.println("RoutingKey:"+envelope.getRoutingKey());
                            System.out.println("properties:"+properties);*/
                            System.out.println("body:"+new String(body));
                            System.out.println("将日志信息打印到控制台.....");
                        }
                    };
                    channel.basicConsume(queue1Name,true,consumer);
            
            
                    //关闭资源?不要
            
                }
            }
        • 交换机的通:用来绑定队列的,指定路由规则,本身不存储消息
        • 与工作队列模式的区别:
          • 工作队列模式不用定义交换机【使用默认交换机""】,发布/订阅模式需要定义交换机。
          • 工作队列模式的生产方是面向队列发送消息,发布/订阅模式的生产方是面向交换机发送消息。
          • 工作队列模式不需要设置,实际上工作队列模式会将队列绑定到默认的交换机,发布/订阅模式需要设置队列和交换机的绑定。
      • 路由模式
        • 2020-03-18_223034
        • 队列与交换机的绑定,不能是任意绑定了,而是要指定一个RoutingKey(路由key)
        • 消息的发送方在向Exchange发送消息时,也必须指定消息的 RoutingKey。
        • Exchange不再把消息交给每一个绑定的队列,而是根据消息的Routing Key进行判断,只有队列的Routing Key与消息的 Routing key完全一致,才会接收到消息
        • 具体实现
          • 生产者
            • public class Producer_Routing {
                  public static void main(String[] args) throws IOException, TimeoutException {
              
                      //1.创建连接工厂
                      ConnectionFactory factory = new ConnectionFactory();
                      //2. 设置参数
                      factory.setHost("172.16.98.133");//ip  默认值 localhost
                      factory.setPort(5672); //端口  默认值 5672
                      factory.setVirtualHost("/itcast");//虚拟机 默认值/
                      factory.setUsername("heima");//用户名 默认 guest
                      factory.setPassword("heima");//密码 默认值 guest
                      //3. 创建连接 Connection
                      Connection connection = factory.newConnection();
                      //4. 创建Channel
                      Channel channel = connection.createChannel();
                     /*
              
                     exchangeDeclare(String exchange, BuiltinExchangeType type, boolean durable, boolean autoDelete, boolean internal, Map<String, Object> arguments)
                     参数:
                      1. exchange:交换机名称
                      2. type:交换机类型
                          DIRECT("direct"),:定向
                          FANOUT("fanout"),:扇形(广播),发送消息到每一个与之绑定队列。
                          TOPIC("topic"),通配符的方式
                          HEADERS("headers");参数匹配
              
                      3. durable:是否持久化
                      4. autoDelete:自动删除
                      5. internal:内部使用。 一般false
                      6. arguments:参数
                      */
              
                     String exchangeName = "test_direct";
                      //5. 创建交换机
                      channel.exchangeDeclare(exchangeName, BuiltinExchangeType.DIRECT,true,false,false,null);
                      //6. 创建队列
                      String queue1Name = "test_direct_queue1";
                      String queue2Name = "test_direct_queue2";
              
                      channel.queueDeclare(queue1Name,true,false,false,null);
                      channel.queueDeclare(queue2Name,true,false,false,null);
                      //7. 绑定队列和交换机
                      /*
                      queueBind(String queue, String exchange, String routingKey)
                      参数:
                          1. queue:队列名称
                          2. exchange:交换机名称
                          3. routingKey:路由键,绑定规则
                              如果交换机的类型为fanout ,routingKey设置为""
                       */
                      //队列1绑定 error
                      channel.queueBind(queue1Name,exchangeName,"error");
                      //队列2绑定 info  error  warning
                      channel.queueBind(queue2Name,exchangeName,"info");
                      channel.queueBind(queue2Name,exchangeName,"error");
                      channel.queueBind(queue2Name,exchangeName,"warning");
              
                      String body = "日志信息:张三调用了delete方法...出错误了。。。日志级别:error...";
                      //8. 发送消息
                      channel.basicPublish(exchangeName,"warning",null,body.getBytes());
              
                      //9. 释放资源
                      channel.close();
                      connection.close();
              
                  }
              }
          • 消费者
            • public class Consumer_Routing1 {
                  public static void main(String[] args) throws IOException, TimeoutException {
              
                      //1.创建连接工厂
                      ConnectionFactory factory = new ConnectionFactory();
                      //2. 设置参数
                      factory.setHost("172.16.98.133");//ip  默认值 localhost
                      factory.setPort(5672); //端口  默认值 5672
                      factory.setVirtualHost("/itcast");//虚拟机 默认值/
                      factory.setUsername("heima");//用户名 默认 guest
                      factory.setPassword("heima");//密码 默认值 guest
                      //3. 创建连接 Connection
                      Connection connection = factory.newConnection();
                      //4. 创建Channel
                      Channel channel = connection.createChannel();
              
              
                      String queue1Name = "test_direct_queue1";
                      String queue2Name = "test_direct_queue2";
              
              
                      /*
                      basicConsume(String queue, boolean autoAck, Consumer callback)
                      参数:
                          1. queue:队列名称
                          2. autoAck:是否自动确认
                          3. callback:回调对象
              
                       */
                      // 接收消息
                      Consumer consumer = new DefaultConsumer(channel){
                          /*
                              回调方法,当收到消息后,会自动执行该方法
              
                              1. consumerTag:标识
                              2. envelope:获取一些信息,交换机,路由key...
                              3. properties:配置信息
                              4. body:数据
              
                           */
                          @Override
                          public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
                            /*  System.out.println("consumerTag:"+consumerTag);
                              System.out.println("Exchange:"+envelope.getExchange());
                              System.out.println("RoutingKey:"+envelope.getRoutingKey());
                              System.out.println("properties:"+properties);*/
                              System.out.println("body:"+new String(body));
                              System.out.println("将日志信息打印到控制台.....");
                          }
                      };
                      channel.basicConsume(queue2Name,true,consumer);
              
              
                      //关闭资源?不要
              
                  }
              }
      • 通配符模式Topic
        • 路由模式需要完全匹配Routing Key,才能收到消息。
          而Topic是能够使用通配符进行部分匹配,只要满足条件的就能收到消息

        • Routingkey 一般都是有一个或多个单词组成,多个单词之间以”.”分割
        • 通配符规则
          • #:匹配一个或多个词
          • *:匹配不多不少恰好1个词
        • 2020-03-18_224233
        • 生产者
          • public class Producer_Topics {
                public static void main(String[] args) throws IOException, TimeoutException {
            
                    //1.创建连接工厂
                    ConnectionFactory factory = new ConnectionFactory();
                    //2. 设置参数
                    factory.setHost("172.16.98.133");//ip  默认值 localhost
                    factory.setPort(5672); //端口  默认值 5672
                    factory.setVirtualHost("/itcast");//虚拟机 默认值/
                    factory.setUsername("heima");//用户名 默认 guest
                    factory.setPassword("heima");//密码 默认值 guest
                    //3. 创建连接 Connection
                    Connection connection = factory.newConnection();
                    //4. 创建Channel
                    Channel channel = connection.createChannel();
                   /*
            
                   exchangeDeclare(String exchange, BuiltinExchangeType type, boolean durable, boolean autoDelete, boolean internal, Map<String, Object> arguments)
                   参数:
                    1. exchange:交换机名称
                    2. type:交换机类型
                        DIRECT("direct"),:定向
                        FANOUT("fanout"),:扇形(广播),发送消息到每一个与之绑定队列。
                        TOPIC("topic"),通配符的方式
                        HEADERS("headers");参数匹配
            
                    3. durable:是否持久化
                    4. autoDelete:自动删除
                    5. internal:内部使用。 一般false
                    6. arguments:参数
                    */
            
                   String exchangeName = "test_topic";
                    //5. 创建交换机
                    channel.exchangeDeclare(exchangeName, BuiltinExchangeType.TOPIC,true,false,false,null);
                    //6. 创建队列
                    String queue1Name = "test_topic_queue1";
                    String queue2Name = "test_topic_queue2";
                    channel.queueDeclare(queue1Name,true,false,false,null);
                    channel.queueDeclare(queue2Name,true,false,false,null);
                    //7. 绑定队列和交换机
                    /*
                    queueBind(String queue, String exchange, String routingKey)
                    参数:
                        1. queue:队列名称
                        2. exchange:交换机名称
                        3. routingKey:路由键,绑定规则
                            如果交换机的类型为fanout ,routingKey设置为""
                     */
            
                    // routing key  系统的名称.日志的级别。
                    //=需求: 所有error级别的日志存入数据库,所有order系统的日志存入数据库
                    channel.queueBind(queue1Name,exchangeName,"#.error");
                    channel.queueBind(queue1Name,exchangeName,"order.*");
                    channel.queueBind(queue2Name,exchangeName,"*.*");
            
                    String body = "日志信息:张三调用了findAll方法...日志级别:info...";
                    //8. 发送消息
                    channel.basicPublish(exchangeName,"goods.error",null,body.getBytes());
            
                    //9. 释放资源
                    channel.close();
                    connection.close();
            
                }
            }
        • 消费者
          • public class Consumer_Topic1 {
                public static void main(String[] args) throws IOException, TimeoutException {
            
                    //1.创建连接工厂
                    ConnectionFactory factory = new ConnectionFactory();
                    //2. 设置参数
                    factory.setHost("172.16.98.133");//ip  默认值 localhost
                    factory.setPort(5672); //端口  默认值 5672
                    factory.setVirtualHost("/itcast");//虚拟机 默认值/
                    factory.setUsername("heima");//用户名 默认 guest
                    factory.setPassword("heima");//密码 默认值 guest
                    //3. 创建连接 Connection
                    Connection connection = factory.newConnection();
                    //4. 创建Channel
                    Channel channel = connection.createChannel();
            
            
                    String queue1Name = "test_topic_queue1";
                    String queue2Name = "test_topic_queue2";
            
            
                    /*
                    basicConsume(String queue, boolean autoAck, Consumer callback)
                    参数:
                        1. queue:队列名称
                        2. autoAck:是否自动确认
                        3. callback:回调对象
            
                     */
                    // 接收消息
                    Consumer consumer = new DefaultConsumer(channel){
                        /*
                            回调方法,当收到消息后,会自动执行该方法
            
                            1. consumerTag:标识
                            2. envelope:获取一些信息,交换机,路由key...
                            3. properties:配置信息
                            4. body:数据
            
                         */
                        @Override
                        public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
                          /*  System.out.println("consumerTag:"+consumerTag);
                            System.out.println("Exchange:"+envelope.getExchange());
                            System.out.println("RoutingKey:"+envelope.getRoutingKey());
                            System.out.println("properties:"+properties);*/
                            System.out.println("body:"+new String(body));
                            System.out.println("将日志信息存入数据库.......");
                        }
                    };
                    channel.basicConsume(queue1Name,true,consumer);
            
            
                    //关闭资源?不要
            
                }
            }
        • Topic主题模式可以实现 Publish/Subscribe发布与订阅模式 和 Routing路由模式 的功能;只是Topic在配置routing key 的时候可以使用通配符,显得更加灵活。
    • 总结
      • 简单模式 HelloWorld:一个生产者、一个消费者,不需要设置交换机(使用默认的交换机)
      • 工作队列模式 Work Queue:一个生产者、多个消费者(竞争关系),不需要设置交换机(使用默认的交换机)
      • 发布订阅模式 Publish/subscribe:需要设置类型为fanout的交换机,并且交换机和队列进行绑定,当发送消息到交换机后,交换机会将消息发送到绑定的队列
      • 路由模式 Routing:需要设置类型为direct的交换机,交换机和队列进行绑定,并且指定routing key,当发送消息到交换机后,交换机会根据routing key将消息发送到对应的队列
      • 通配符模式 Topic:需要设置类型为topic的交换机,交换机和队列进行绑定,并且指定通配符方式的routing key,当发送消息到交换机后,交换机会根据routing key将消息发送到对应的队列
    • 生产者整体开发步骤
      • ·创建连接工厂
        • 设置参数:ip,端口,虚拟机,用户名,密码
      • 通过工厂获取连接
      • 通过连接获取channel
      • 通过channel声明交换机
      • 通过channel声明队列
      • 通过channel把队列绑定到交换机
        • 队列名称
        • 交换机名称
        • 路由key
      • 发送消息
    • 消费者开发步骤
      • ·创建连接工厂
        • 设置参数:ip,端口,虚拟机,用户名,密码
      • 通过工厂获取连接
      • 通过连接获取channel
      • 通过channel声明交换机
      • 通过channel声明队列
        • 监听消息,回调对象,在回调方法中去处理消息
      • spring整合开发
        • 生产者工程
          • 依赖
            •  <dependency>
                          <groupId>org.springframework.amqp</groupId>
                          <artifactId>spring-rabbit</artifactId>
                          <version>2.1.8.RELEASE</version>
                      </dependency>
          • rabbitmq.properties
            • #注意修改成自己的rabbitmq服务器信息
              rabbitmq.host=172.16.98.133
              rabbitmq.port=5672
              rabbitmq.username=heima
              rabbitmq.password=heima
              rabbitmq.virtual-host=/itcast
          • spring-rabbitmq-producer.xml
            • <?xml version="1.0" encoding="UTF-8"?>
              <beans xmlns="http://www.springframework.org/schema/beans"
                     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                     xmlns:context="http://www.springframework.org/schema/context"
                     xmlns:rabbit="http://www.springframework.org/schema/rabbit"
                     xsi:schemaLocation="http://www.springframework.org/schema/beans
                     http://www.springframework.org/schema/beans/spring-beans.xsd
                     http://www.springframework.org/schema/context
                     https://www.springframework.org/schema/context/spring-context.xsd
                     http://www.springframework.org/schema/rabbit
                     http://www.springframework.org/schema/rabbit/spring-rabbit.xsd">
                  <!--加载配置文件-->
                  <context:property-placeholder location="classpath:rabbitmq.properties"/>
              
                  <!-- 定义rabbitmq connectionFactory -->
                  <rabbit:connection-factory id="connectionFactory" host="${rabbitmq.host}"
                                             port="${rabbitmq.port}"
                                             username="${rabbitmq.username}"
                                             password="${rabbitmq.password}"
                                             virtual-host="${rabbitmq.virtual-host}"/>
                  <!--定义管理交换机、队列-->
                  <rabbit:admin connection-factory="connectionFactory"/>
              
                  <!--定义持久化队列,不存在则自动创建;不绑定到交换机则绑定到默认交换机
                  默认交换机类型为direct,名字为:"",路由键为队列的名称
                  -->
                  <!--
                      id:bean的名称
                      name:queue的名称
                      auto-declare:自动创建
                      auto-delete:自动删除。 最后一个消费者和该队列断开连接后,自动删除队列
                      exclusive:是否独占
                      durable:是否持久化
                  -->
              
                  <rabbit:queue id="spring_queue" name="spring_queue"    auto-declare="true"/>
              
                  <!-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~广播;所有队列都能收到消息~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -->
                  <!--定义广播交换机中的持久化队列,不存在则自动创建-->
                  <rabbit:queue id="spring_fanout_queue_1" name="spring_fanout_queue_1" auto-declare="true"/>
              
                  <!--定义广播交换机中的持久化队列,不存在则自动创建-->
                  <rabbit:queue id="spring_fanout_queue_2" name="spring_fanout_queue_2" auto-declare="true"/>
              
                  <!--定义广播类型交换机;并绑定上述两个队列-->
                  <rabbit:fanout-exchange id="spring_fanout_exchange" name="spring_fanout_exchange"  auto-declare="true">
                      <rabbit:bindings>
                          <rabbit:binding  queue="spring_fanout_queue_1"  />
                          <rabbit:binding queue="spring_fanout_queue_2"/>
                      </rabbit:bindings>
                  </rabbit:fanout-exchange>
              
                  <!--<rabbit:direct-exchange name="aa" >
                      <rabbit:bindings>
                          &lt;!&ndash;direct 类型的交换机绑定队列  key :路由key  queue:队列名称&ndash;&gt;
                          <rabbit:binding queue="spring_queue" key="xxx"></rabbit:binding>
                      </rabbit:bindings>
              
                  </rabbit:direct-exchange>-->
              
                  <!-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~通配符;*匹配一个单词,#匹配多个单词 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -->
                  <!--定义广播交换机中的持久化队列,不存在则自动创建-->
                  <rabbit:queue id="spring_topic_queue_star" name="spring_topic_queue_star"  auto-declare="true"/>
                  <!--定义广播交换机中的持久化队列,不存在则自动创建-->
                  <rabbit:queue id="spring_topic_queue_well" name="spring_topic_queue_well" auto-declare="true"/>
                  <!--定义广播交换机中的持久化队列,不存在则自动创建-->
                  <rabbit:queue id="spring_topic_queue_well2" name="spring_topic_queue_well2" auto-declare="true"/>
              
                  <rabbit:topic-exchange id="spring_topic_exchange"  name="spring_topic_exchange" auto-declare="true">
                      <rabbit:bindings>
                          <rabbit:binding pattern="heima.*"  queue="spring_topic_queue_star"/>
                          <rabbit:binding pattern="heima.#" queue="spring_topic_queue_well"/>
                          <rabbit:binding pattern="itcast.#" queue="spring_topic_queue_well2"/>
                      </rabbit:bindings>
                  </rabbit:topic-exchange>
              
                  <!--定义rabbitTemplate对象操作可以在代码中方便发送消息-->
                  <rabbit:template id="rabbitTemplate" connection-factory="connectionFactory"/>
              </beans>
          • 测试类
            • @RunWith(SpringJUnit4ClassRunner.class)
              @ContextConfiguration(locations = "classpath:spring-rabbitmq-producer.xml")
              public class ProducerTest {
              
                  //1.注入 RabbitTemplate
                  @Autowired
                  private RabbitTemplate rabbitTemplate;
              
              
                  @Test
                  public void testHelloWorld(){
                      //2.发送消息
              
                      rabbitTemplate.convertAndSend("spring_queue","hello world spring....");
                  }
              
              
                  /**
                   * 发送fanout消息
                   */
                  @Test
                  public void testFanout(){
                      //2.发送消息
              
                      rabbitTemplate.convertAndSend("spring_fanout_exchange","","spring fanout....");
                  }
              
              
                  /**
                   * 发送topic消息
                   */
                  @Test
                  public void testTopics(){
                      //2.发送消息
              
                      rabbitTemplate.convertAndSend("spring_topic_exchange","heima.hehe.haha","spring topic....");
                  }
              }
        • 消费者工程
          • rabbitmq.properties
            • #注意修改成自己的rabbitmq服务器信息
              rabbitmq.host=172.16.98.133
              rabbitmq.port=5672
              rabbitmq.username=heima
              rabbitmq.password=heima
              rabbitmq.virtual-host=/itcast
          • spring-rabbitmq-consumer.xml
            • <?xml version="1.0" encoding="UTF-8"?>
              <beans xmlns="http://www.springframework.org/schema/beans"
                     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                     xmlns:context="http://www.springframework.org/schema/context"
                     xmlns:rabbit="http://www.springframework.org/schema/rabbit"
                     xsi:schemaLocation="http://www.springframework.org/schema/beans
                     http://www.springframework.org/schema/beans/spring-beans.xsd
                     http://www.springframework.org/schema/context
                     https://www.springframework.org/schema/context/spring-context.xsd
                     http://www.springframework.org/schema/rabbit
                     http://www.springframework.org/schema/rabbit/spring-rabbit.xsd">
                  <!--加载配置文件-->
                  <context:property-placeholder location="classpath:rabbitmq.properties"/>
              
                  <!-- 定义rabbitmq connectionFactory -->
                  <rabbit:connection-factory id="connectionFactory" host="${rabbitmq.host}"
                                             port="${rabbitmq.port}"
                                             username="${rabbitmq.username}"
                                             password="${rabbitmq.password}"
                                             virtual-host="${rabbitmq.virtual-host}"/>
              
                  <bean id="springQueueListener" class="com.itheima.rabbitmq.listener.SpringQueueListener"/>
                  <!--<bean id="fanoutListener1" class="com.itheima.rabbitmq.listener.FanoutListener1"/>
                  <bean id="fanoutListener2" class="com.itheima.rabbitmq.listener.FanoutListener2"/>
                  <bean id="topicListenerStar" class="com.itheima.rabbitmq.listener.TopicListenerStar"/>
                  <bean id="topicListenerWell" class="com.itheima.rabbitmq.listener.TopicListenerWell"/>
                  <bean id="topicListenerWell2" class="com.itheima.rabbitmq.listener.TopicListenerWell2"/>
              -->
                  <rabbit:listener-container connection-factory="connectionFactory" auto-declare="true">
                      <rabbit:listener ref="springQueueListener" queue-names="spring_queue"/>
                     <!-- <rabbit:listener ref="fanoutListener1" queue-names="spring_fanout_queue_1"/>
                      <rabbit:listener ref="fanoutListener2" queue-names="spring_fanout_queue_2"/>
                      <rabbit:listener ref="topicListenerStar" queue-names="spring_topic_queue_star"/>
                      <rabbit:listener ref="topicListenerWell" queue-names="spring_topic_queue_well"/>
                      <rabbit:listener ref="topicListenerWell2" queue-names="spring_topic_queue_well2"/>-->
                  </rabbit:listener-container>
              </beans>
          • 创建消息监听类
            • public class SpringQueueListener implements MessageListener {
                  @Override
                  public void onMessage(Message message) {
                      //打印消息
                      System.out.println("消息内容:" + new String(message.getBody()));
                      System.out.println("交换机:" + message.getMessageProperties().getReceivedExchange());
                      System.out.println("路由Key:" + message.getMessageProperties().getReceivedRoutingKey());
                      System.out.println("队列名:" + message.getMessageProperties().getConsumerQueue());
                  }
              }
          • 测试类
            • @RunWith(SpringJUnit4ClassRunner.class)
              @ContextConfiguration(locations = "classpath:spring-rabbitmq-consumer.xml")
              public class ConsumerTest {
              
                  @Test
                  public void test1(){
                      boolean flag = true;
                      while (true){
              
                      }
                  }
              }
              
        • springboot整合
          • 生产者工程
            • 引入依赖
              • <!--2. rabbitmq-->
                    <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>
            • 配置文件 application.yml
              • # 配置RabbitMQ的基本信息  ip 端口 username  password..
                spring:
                  rabbitmq:
                    host: 172.16.98.133 # ip
                    port: 5672
                    username: guest
                    password: guest
                    virtual-host: /
            • 引导类
              • @SpringBootApplication
                public class ProducerApplication {
                
                    public static void main(String[] args) {
                        SpringApplication.run(ProducerApplication.class);
                    }
                }
            • 配置类
              • @Configuration
                public class RabbitMQConfig {
                
                    public static final String EXCHANGE_NAME = "boot_topic_exchange";
                    public static final String QUEUE_NAME = "boot_queue";
                
                    //1.交换机
                    @Bean("bootExchange")
                    public Exchange bootExchange(){
                        return ExchangeBuilder.topicExchange(EXCHANGE_NAME).durable(true).build();
                    }
                
                
                    //2.Queue 队列
                    @Bean("bootQueue")
                    public Queue bootQueue(){
                        return QueueBuilder.durable(QUEUE_NAME).build();
                    }
                
                    //3. 队列和交互机绑定关系 Binding
                    /*
                        1. 知道哪个队列
                        2. 知道哪个交换机
                        3. routing key
                     */
                    @Bean
                    public Binding bindQueueExchange(@Qualifier("bootQueue") Queue queue, @Qualifier("bootExchange") Exchange exchange){
                        return BindingBuilder.bind(queue).to(exchange).with("boot.#").noargs();
                    }
                
                
                }
            • 测试类
              • @SpringBootTest
                @RunWith(SpringRunner.class)
                public class ProducerTest {
                
                    //1.注入RabbitTemplate
                    @Autowired
                    private RabbitTemplate rabbitTemplate;
                
                    @Test
                    public void testSend(){
                
                        rabbitTemplate.convertAndSend(RabbitMQConfig.EXCHANGE_NAME,"boot.haha","boot mq hello~~~");
                    }
                }
          • 消费者
            • 引入依赖
              •     <dependency>
                        <groupId>org.springframework.boot</groupId>
                        <artifactId>spring-boot-starter-amqp</artifactId>
                    </dependency>
                    <dependency>
            • 配置文件 application.yml
              • # 配置RabbitMQ的基本信息  ip 端口 username  password..
                spring:
                  rabbitmq:
                    host: 172.16.98.133 # ip
                    port: 5672
                    username: guest
                    password: guest
                    virtual-host: /
            • 引导类
              • @SpringBootApplication
                public class ConsumerSpringbootApplication {
                
                    public static void main(String[] args) {
                        SpringApplication.run(ConsumerSpringbootApplication.class, args);
                    }
                
                }
                
            • 消息监听类
              • @Component
                public class RabbimtMQListener {
                
                    @RabbitListener(queues = "boot_queue")
                    public void ListenerQueue(Message message){
                        //System.out.println(message);
                        System.out.println(new String(message.getBody()));
                    }
                
                }
                

      posted on 2020-03-18 10:45  赟麟  阅读(207)  评论(0编辑  收藏  举报

      导航