安装及配置

安装

1、安装erlang,以管理员身份运行。
2、安装rabbitmq-server,以管理员身份运行。
3、配置环境变量
image.png
配置:elang-home:,指定你的erlang的安装目录
image.png
添加到path:
image.png
cmd到rabbitmq-server的 sbin目录下 打开cmd命令行工具:

cd C:\Program Files\RabbitMQ Server\rabbitmq_server-3.7.4\sbin

执行命令:

rabbitmq-plugins.bat enable rabbitmq_management

image.png
重启rabbitmq服务器:
此电脑–>右击 点击管理界面–>双击服务和应用程序–>双击 服务–>点击重启按钮即可
image.png
浏览器中输入localhost:15672 输 guest/guest:
image.png

RabbitMq入门

示例工程

  • 依赖

    <dependency>
      <groupId>com.rabbitmq</groupId>
      <artifactId>amqp-client</artifactId>
      <version>5.6.0</version>
    </dependency>
  • 生产者

    //创建链接工厂对象
    //设置RabbitMQ服务主机地址,默认localhost
    //设置RabbitMQ服务端口,默认5672
    //设置虚拟主机名字,默认/
    //设置用户连接名,默认guest
    //设置链接密码,默认guest
    //创建链接
    //创建频道
    //声明队列
    //创建消息
    //消息发送
    //关闭资源
    public class Producer {
    
      /***
       * 消息生产者
       * @param args
       * @throws IOException
       * @throws TimeoutException
       */
      public static void main(String[] args) throws IOException, TimeoutException {
          //创建链接工厂对象
          ConnectionFactory connectionFactory = new ConnectionFactory();
    
          //设置RabbitMQ服务主机地址,默认localhost
          connectionFactory.setHost("localhost");
    
          //设置RabbitMQ服务端口,默认5672
          connectionFactory.setPort(5672);
    
          //设置虚拟主机名字,默认/
          connectionFactory.setVirtualHost("/daryl");
    
          //设置用户连接名,默认guest
          connectionFactory.setUsername("admin");
    
          //设置链接密码,默认guest
          connectionFactory.setPassword("admin");
    
          //创建链接
          Connection connection = connectionFactory.newConnection();
    
          //创建频道
          Channel channel = connection.createChannel();
    
          /**
           * 声明队列
           * 参数1:队列名称
           * 参数2:是否定义持久化队列
           * 参数3:是否独占本次连接
           * 参数4:是否在不使用的时候自动删除队列
           * 参数5:队列其它参数
           * **/
          channel.queueDeclare("simple_queue",true,false,false,null);
    
          //创建消息
          String message = "hello world!";
    
          /**
           * 消息发送
           * 参数1:交换机名称,如果没有指定则使用默认Default Exchage
           * 参数2:路由key,简单模式可以传递队列名称
           * 参数3:消息其它属性
           * 参数4:消息内容
           */
          channel.basicPublish("","simple_queue",null,message.getBytes());
    
          //关闭资源
          channel.close();
          connection.close();
      }
    }

    在执行上述的消息发送之后;可以登录rabbitMQ的管理控制台,可以发现队列和其消息:
    如果想查看消息,可以点击队列名称->Get Messages

  • 消费者

    //创建链接工厂对象
    //设置RabbitMQ服务主机地址,默认localhost
    //设置RabbitMQ服务端口,默认5672
    //设置虚拟主机名字,默认/
    //设置用户连接名,默认guest
    //设置链接密码,默认guest
    //创建链接
    //创建频道
    //创建队列
    //创建消费者,并设置消息处理
    //消息监听
    //关闭资源(不建议关闭,建议一直监听消息)
    public class Consumer {
    
      /***
       * 消息消费者
       * @param args
       * @throws IOException
       * @throws TimeoutException
       */
      public static void main(String[] args) throws IOException, TimeoutException {
          //创建链接工厂对象
          ConnectionFactory connectionFactory = new ConnectionFactory();
    
          //设置RabbitMQ服务主机地址,默认localhost
          connectionFactory.setHost("localhost");
    
          //设置RabbitMQ服务端口,默认5672
          connectionFactory.setPort(5672);
    
          //设置虚拟主机名字,默认/
          connectionFactory.setVirtualHost("/daryl");
    
          //设置用户连接名,默认guest
          connectionFactory.setUsername("admin");
    
          //设置链接密码,默认guest
          connectionFactory.setPassword("admin");
    
          //创建链接
          Connection connection = connectionFactory.newConnection();
    
          //创建频道
          Channel channel = connection.createChannel();
    
          //创建队列
          channel.queueDeclare("simple_queue",true,false,false,null);
    
          //创建消费者,并设置消息处理
          DefaultConsumer defaultConsumer = new DefaultConsumer(channel){
              /***
               * @param consumerTag   消息者标签,在channel.basicConsume时候可以指定
               * @param envelope      消息包的内容,可从中获取消息id,消息routingkey,交换机,消息和重传标志(收到消息失败后是否需要重新发送)
               * @param properties    属性信息
               * @param body           消息
               * @throws IOException
               */
              @Override
              public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
                  //路由的key
                  String routingKey = envelope.getRoutingKey();
                  //获取交换机信息
                  String exchange = envelope.getExchange();
                  //获取消息ID
                  long deliveryTag = envelope.getDeliveryTag();
                  //获取消息信息
                  String message = new String(body,"UTF-8");
                  System.out.println("routingKey:"+routingKey+",exchange:"+exchange+",deliveryTag:"+deliveryTag+",message:"+message);
              }
          };
    
          /**
           * 消息监听
           * 参数1:队列名称
           * 参数2:是否自动确认,设置为true为表示消息接收到自动向mq回复接收到了,mq接收到回复会删除消息,设置为false则需要手动确认
           * 参数3:消息接收到后回调
           */
          channel.basicConsume("simple_queue",true,defaultConsumer);
    
          //关闭资源(不建议关闭,建议一直监听消息)
          //channel.close();
          //connection.close();
      }
    }

    上述的入门案例中中其实使用的是如下的简单模式:
    image.png

    RabitMq的工作模式

    Work queues工作队列模式

    image.png
    Work Queues与入门程序的简单模式相比,多了一个或一些消费端,多个消费端共同消费同一个队列中的消息。
    应用场景:对于 任务过重或任务较多情况使用工作队列可以提高任务处理的速度。
    代码:
    Work Queues与入门程序的简单模式的代码是几乎一样的;可以完全复制,并复制多一个消费者进行多个消费者同时消费消息的测试。
    生产者:

    public class WorkProducer {
    
      /***
       * 消息生产者
       * @param args
       * @throws IOException
       * @throws TimeoutException
       */
      public static void main(String[] args) throws IOException, TimeoutException {
          //创建链接
          Connection connection = ConnectionUtil.getConnection();
    
          //创建频道
          Channel channel = connection.createChannel();
    
          /**
           * 声明队列
           * 参数1:队列名称
           * 参数2:是否定义持久化队列
           * 参数3:是否独占本次连接
           * 参数4:是否在不使用的时候自动删除队列
           * 参数5:队列其它参数
           * **/
          channel.queueDeclare("work_queue",true,false,false,null);
    
          for (int i = 0; i < 10; i++) {
              String message = "hello world"+i;
              channel.basicPublish("","work_queue",null,message.getBytes());
          }
    
          //关闭资源
          channel.close();
          connection.close();
      }
    }

    消费者One:

    public class WorkConsumerOne {
    
      /***
       * 消息消费者
       * @param args
       * @throws IOException
       * @throws TimeoutException
       */
      public static void main(String[] args) throws IOException, TimeoutException {
          //创建链接
          Connection connection = ConnectionUtil.getConnection();
    
          //创建频道
          Channel channel = connection.createChannel();
    
          //创建队列
          channel.queueDeclare("work_queue",true,false,false,null);
    
          //创建消费者,并设置消息处理
          DefaultConsumer defaultConsumer = new DefaultConsumer(channel){
              /***
               * @param consumerTag   消息者标签,在channel.basicConsume时候可以指定
               * @param envelope      消息包的内容,可从中获取消息id,消息routingkey,交换机,消息和重传标志(收到消息失败后是否需要重新发送)
               * @param properties    属性信息
               * @param body           消息
               * @throws IOException
               */
              @Override
              public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
                  //路由的key
                  String routingKey = envelope.getRoutingKey();
                  //获取交换机信息
                  String exchange = envelope.getExchange();
                  //获取消息ID
                  long deliveryTag = envelope.getDeliveryTag();
                  //获取消息信息
                  String message = new String(body,"UTF-8");
                  System.out.println("Work-One:routingKey:"+routingKey+",exchange:"+exchange+",deliveryTag:"+deliveryTag+",message:"+message);
              }
          };
    
          /**
           * 消息监听
           * 参数1:队列名称
           * 参数2:是否自动确认,设置为true为表示消息接收到自动向mq回复接收到了,mq接收到回复会删除消息,设置为false则需要手动确认
           * 参数3:消息接收到后回调
           */
          channel.basicConsume("work_queue",true,defaultConsumer);
    
          //关闭资源(不建议关闭,建议一直监听消息)
          //channel.close();
          //connection.close();
      }
    }

    消费者Two:

    public class WorkConsumerTwo {
    
      /***
       * 消息消费者
       * @param args
       * @throws IOException
       * @throws TimeoutException
       */
      public static void main(String[] args) throws IOException, TimeoutException {
          //创建链接
          Connection connection = ConnectionUtil.getConnection();
    
          //创建频道
          Channel channel = connection.createChannel();
    
          //创建队列
          channel.queueDeclare("work_queue",true,false,false,null);
    
          //创建消费者,并设置消息处理
          DefaultConsumer defaultConsumer = new DefaultConsumer(channel){
              /***
               * @param consumerTag   消息者标签,在channel.basicConsume时候可以指定
               * @param envelope      消息包的内容,可从中获取消息id,消息routingkey,交换机,消息和重传标志(收到消息失败后是否需要重新发送)
               * @param properties    属性信息
               * @param body           消息
               * @throws IOException
               */
              @Override
              public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
                  //路由的key
                  String routingKey = envelope.getRoutingKey();
                  //获取交换机信息
                  String exchange = envelope.getExchange();
                  //获取消息ID
                  long deliveryTag = envelope.getDeliveryTag();
                  //获取消息信息
                  String message = new String(body,"UTF-8");
                  System.out.println("Work-Two:routingKey:"+routingKey+",exchange:"+exchange+",deliveryTag:"+deliveryTag+",message:"+message);
              }
          };
    
          /**
           * 消息监听
           * 参数1:队列名称
           * 参数2:是否自动确认,设置为true为表示消息接收到自动向mq回复接收到了,mq接收到回复会删除消息,设置为false则需要手动确认
           * 参数3:消息接收到后回调
           */
          channel.basicConsume("work_queue",true,defaultConsumer);
    
          //关闭资源(不建议关闭,建议一直监听消息)
          //channel.close();
          //connection.close();
      }
    }

    测试:
    启动两个消费者,然后再启动生产者发送消息;到IDEA的两个消费者对应的控制台查看是否竞争性的接收到消息。
    image.png
    image.png
    小结:
    在一个队列中如果有多个消费者,那么消费者之间对于同一个消息的关系是竞争的关系。

    订阅模式类型

    image.png
    前面2个案例中,只有3个角色:

    P:生产者,也就是要发送消息的程序
    C:消费者:消息的接受者,会一直等待消息到来。
    Queue:消息队列,图中红色部分

    而在订阅模型中,多了一个exchange角色,而且过程略有变化:

    P:生产者,也就是要发送消息的程序,但是不再发送到队列中,而是发给X(交换机)
    C:消费者,消息的接受者,会一直等待消息到来。
    Queue:消息队列,接收消息、缓存消息。
    Exchange:交换机,图中的X。一方面,接收生产者发送的消息。另一方面,知道如何处理消息,例如递交给某个特别队列、递交给所有队列、或是将消息丢弃。到底如何操作,取决于Exchange的类型。Exchange有常见以下3种类型:
      Fanout:广播,将消息交给所有绑定到交换机的队列
      Direct:定向,把消息交给符合指定routing key 的队列
      Topic:通配符,把消息交给符合routing pattern(路由模式) 的队列

    Exchange(交换机)只负责转发消息,不具备存储消息的能力,因此如果没有任何队列与Exchange绑定,或者没有符合路由规则的队列,那么消息会丢失!


慈祥的茶壶
1 声望1 粉丝

引用和评论

0 条评论