RabbitMQ学习笔记(三)简单队列、工作队列(Java编写)

RabbitMQ学习笔记(三)简单队列、工作队列(Java编写)

1、添加用户

打开控制台,选择admin一栏(按照要求填写信息)

RabbitMQ学习笔记(三)简单队列、工作队列(Java编写)_第1张图片

2、用户角色

  • 超级管理员(administrator)
    可登陆管理控制台,可查看所有的信息,并且可以对用户,策略(policy)进行操作。
  • 监控者(monitoring)
    可登陆管理控制台,同时可以查看rabbitmq节点的相关信息(进程数,内存使用情况,磁盘使用情况等)
  • 策略制定者(policymaker)
    可登陆管理控制台, 同时可以对policy进行管理。但无法查看节点的相关信息(上图红框标识的部分)。
  • 普通管理者(management)
    仅可登陆管理控制台,无法看到节点信息,也无法对策略进行管理。
  • 其他
    无法登陆管理控制台,通常就是普通的生产者和消费者。

3、添加Virtual Host

Virtual Host可以理解为mysql中的数据库。
RabbitMQ学习笔记(三)简单队列、工作队列(Java编写)_第2张图片

为添加的用户,添加新建的Virtual Host权限

RabbitMQ学习笔记(三)简单队列、工作队列(Java编写)_第3张图片
RabbitMQ学习笔记(三)简单队列、工作队列(Java编写)_第4张图片

4、简单队列

RabbitMQ学习笔记(三)简单队列、工作队列(Java编写)_第5张图片

p为生产者,生产消息。消息可以为String字符串

红色的为FIFO队列(先进先出)

c为消费者,也就是从队列里面拿取消息

4.1、代码编写

准备依赖

<dependency>
   <groupId>com.rabbitmqgroupId>
   <artifactId>amqp-clientartifactId>
   <version>5.9.0version>
dependency>

编写获取RabbitMQ连接的工具类

public class ConnectUtil {

    public static Connection getConnection() throws Exception {
        //定义连接工厂
        ConnectionFactory factory = new ConnectionFactory();
        //设置服务地址
        factory.setHost("localhost");
        //端口
        factory.setPort(5672);
        //设置账号信息,用户名、密码、vhost
        factory.setVirtualHost("/xiao");
        factory.setUsername("xiao");
        factory.setPassword("123");
        // 通过工程获取连接
        Connection connection = factory.newConnection();
        return connection;
    }
}

编写生产者的代码(生产者的queue_name和消费者的queue_name一致,保证是从一个队列生产或消费消息)

public class Send {
    private static final String QUEUE_NAME = "simple_queue";

    public static void main(String[] args) throws Exception {
        //获得连接
        Connection connection = ConnectUtil.getConnection();
        //获得管道
        Channel channel = connection.createChannel();
        //声明队列
        channel.queueDeclare(QUEUE_NAME,false,false,false,null);
        //设置消息内容
        channel.basicPublish("",QUEUE_NAME,null , "hello word!".getBytes());

        System.out.println("[send] hello word!");
        channel.close();
        connection.close();
    }
}

编写消费者代码

public class Receive {
    private static final String QUEUE_NAME = "simple_queue";

    public static void main(String[] args) throws Exception {
        //获得连接
        Connection connection = ConnectUtil.getConnection();
        //获得管道
        Channel channel = connection.createChannel();
        //声明队列
        channel.queueDeclare(QUEUE_NAME,false,false,false,null);
        Consumer consumer = new DefaultConsumer(channel) {
            @Override
            public void handleDelivery(String s, Envelope envelope, AMQP.BasicProperties basicProperties, byte[] bytes) throws IOException {
                System.out.println(new String(bytes , "utf-8"));
            }
        };
        // 监听队列,false表示手动返回完成状态,true表示自动
        channel.basicConsume(QUEUE_NAME, true, consumer);

    }
}

5、工作队列

RabbitMQ学习笔记(三)简单队列、工作队列(Java编写)_第6张图片
Simple队列是生产者与消费者一对一的关系。在实际开发中,我们经常遇到多个消费者,我们可以想象,生产者发送消息是毫不费力的,然而消费者获取消息通常还需要进行一系列的业务处理,这显然需要一段时间,这时候消息队列可能就会积压很多消息。

5.1、轮询分发

所谓轮询分发就是队列会轮流发送消息给消费者。如果现在队列里面有50条消息,那么轮询分发会使两个消费者获得的消息条数一样,每个消费者都可获得25条消息。

生产者代码

public class Send {
    private static final String QUEUE_NAME = "work_queue";

    public static void main(String[] args) throws Exception {
        //获得连接
        Connection connection = ConnectUtil.getConnection();
        //获得管道
        Channel channel = connection.createChannel();
        //声明队列
        channel.queueDeclare(QUEUE_NAME,false,false,false,null);
        for (int i = 0; i < 50; i++) {
            String msg = "["+i+"] hello word!";

            //设置消息内容
            channel.basicPublish("",QUEUE_NAME,null , msg.getBytes());
            System.out.println("[send] hello word!");
        }

        channel.close();
        connection.close();
    }
}

消费者1号

public class ReceiveOne {
    private static final String QUEUE_NAME = "work_queue";

    public static void main(String[] args) throws Exception {
        //获得连接
        Connection connection = ConnectUtil.getConnection();
        //获得管道
        Channel channel = connection.createChannel();
        //声明队列
        channel.queueDeclare(QUEUE_NAME,false,false,false,null);

        Consumer consumer = new DefaultConsumer(channel) {
            @Override
            public void handleDelivery(String s, Envelope envelope, AMQP.BasicProperties basicProperties, byte[] bytes) throws IOException {
                System.out.println(new String(bytes , "utf-8"));

                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        };
        // 监听队列,false表示手动返回完成状态,true表示自动
        channel.basicConsume(QUEUE_NAME, true, consumer);

    }
}

消费者2号

public class ReceiveTwo {
    private static final String QUEUE_NAME = "work_queue";

    public static void main(String[] args) throws Exception {
        //获得连接
        Connection connection = ConnectUtil.getConnection();
        //获得管道
        Channel channel = connection.createChannel();
        //声明队列
        channel.queueDeclare(QUEUE_NAME,false,false,false,null);
        Consumer consumer = new DefaultConsumer(channel) {
            @Override
            public void handleDelivery(String s, Envelope envelope, AMQP.BasicProperties basicProperties, byte[] bytes) throws IOException {
                System.out.println(new String(bytes , "utf-8"));

                try {
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        };
        // 监听队列,false表示手动返回完成状态,true表示自动
        channel.basicConsume(QUEUE_NAME, true, consumer);

    }
}

先开启两个消费者、在开启生产者

虽然上面的分配法方式也还行,但是有个问题就是:现在的这2个消费者,因为消费能力的不同,所以消费的效率也不同。按照轮询的方式,任务交给了第二个消费者,所以一直在忙个不停。任务交给另一个消费者,则立即完成任务,然后闲得不行。而RabbitMQ则是不了解这些的。这是因为当消息进入队列,RabbitMQ就会分派消息。它不看消费者为应答的数目,只是盲目的将消息发给轮询指定的消费者。

5.2、公平分发(能者多劳)

生产者代码

public class Send {
    private static final String QUEUE_NAME = "work_queue";

    public static void main(String[] args) throws Exception {
        //获得连接
        Connection connection = ConnectUtil.getConnection();
        //获得管道
        Channel channel = connection.createChannel();
        //声明队列
        channel.queueDeclare(QUEUE_NAME,false,false,false,null);
        for (int i = 0; i < 50; i++) {
            String msg = "["+i+"] hello word!";

            //设置消息内容
            channel.basicPublish("",QUEUE_NAME,null , msg.getBytes());
            System.out.println("[send] hello word!");
        }

        channel.close();
        connection.close();
    }
}

消费者1号

public class ReceiveOne {
    private static final String QUEUE_NAME = "work_queue";

    public static void main(String[] args) throws Exception {
        //获得连接
        Connection connection = ConnectUtil.getConnection();
        //获得管道
        final Channel channel = connection.createChannel();
        //声明队列
        channel.queueDeclare(QUEUE_NAME,false,false,false,null);
        //保证一次只接受一个消息,处理完以后在请求下一个
        channel.basicQos(1);
        Consumer consumer = new DefaultConsumer(channel) {
            @Override
            public void handleDelivery(String s, Envelope envelope, AMQP.BasicProperties basicProperties, byte[] bytes) throws IOException {
                System.out.println(new String(bytes , "utf-8"));

                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }finally {
                    channel.basicAck(envelope.getDeliveryTag() , false);
                }
            }
        };
        // 监听队列,false表示手动返回完成状态,true表示自动应答 false表示手动应答
        channel.basicConsume(QUEUE_NAME, false, consumer);

    }
}

消费者2号

public class ReceiveTwo {
    private static final String QUEUE_NAME = "work_queue";

    public static void main(String[] args) throws Exception {
        //获得连接
        Connection connection = ConnectUtil.getConnection();
        //获得管道
        final Channel channel = connection.createChannel();
        //声明队列
        channel.queueDeclare(QUEUE_NAME,false,false,false,null);
        //保证一次只接受一个消息,处理完以后在请求下一个
        channel.basicQos(1);
        Consumer consumer = new DefaultConsumer(channel) {
            @Override
            public void handleDelivery(String s, Envelope envelope, AMQP.BasicProperties basicProperties, byte[] bytes) throws IOException {
                System.out.println(new String(bytes , "utf-8"));

                try {
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }finally {
                    channel.basicAck(envelope.getDeliveryTag() , false);
                }
            }
        };
        // 监听队列,false表示手动返回完成状态,true表示自动
        channel.basicConsume(QUEUE_NAME, false, consumer);

    }
}

你可能感兴趣的:(RabbitMQ,队列,rabbitmq)