java + maven 学习RabbitMQ (二)

工作队列

一个队列bind多个消费者

/**
 * 生产者
 */
public class WorkQueueProvider {

    private static final String QUEUE_NAME = "test_work_queue";

    public static void main(String[] args) throws IOException, TimeoutException {
        Connection connection = RabbitMQUtil.getConnection();
        Channel channel = connection.createChannel();
        //队列声明
        channel.queueDeclare(QUEUE_NAME,false,false,false,null);

        for (int i = 0; i < 50; i++){
            StringBuffer buffer = new StringBuffer("Hello,");
            buffer.append(i);
            channel.basicPublish("",QUEUE_NAME,null,buffer.toString().getBytes());
             //消息持久化
//           channel.basicPublish("exchange.persistent", "persistent", MessageProperties.PERSISTENT_TEXT_PLAIN, "persistent_test_message".getBytes());
        }

        RabbitMQUtil.close(connection, channel);
    }
    
}

/**
 * 消费者1
 */
public class WorkQueueConsumerOne {

    private static final String QUEUE_NAME = "test_work_queue";

    public static void main(String[] args) throws IOException, TimeoutException {

        Connection connection = RabbitMQUtil.getConnection();

        final Channel channel = connection.createChannel();
        /**'
         *  声明队列,虽然已经在生产者中声明过了,但这样写并不会有什么问题
         *  之所以在这里再声明,是为了保证在生产者程序未运行的情况下,队列也被声明
         *  这样消费者程序运行时不会报队列未声明的错误
         */
        channel.queueDeclare(QUEUE_NAME,false,false,false,null);
        
        DefaultConsumer consumer = new DefaultConsumer(channel) {

            @Override
            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {

                String msg = new String(body, "utf-8");
                System.out.println("收到消息:"+msg);

                try {
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }finally {
                    channel.basicAck(envelope.getDeliveryTag(),false);
                }

            }
        };
       
        //关闭消息自动ack
        boolean autoAck = false;
        channel.basicConsume(QUEUE_NAME,autoAck,consumer);

    }
}

/**
 * 消费者2
 */
public class WorkQueueConsumerTwo {

    private static final String QUEUE_NAME = "test_work_queue";

    public static void main(String[] args) throws IOException, TimeoutException {

        Connection connection = RabbitMQUtil.getConnection();
        final Channel channel = connection.createChannel();
        channel.queueDeclare(QUEUE_NAME,false,false,false,null);

        DefaultConsumer consumer = new DefaultConsumer(channel) {

            @Override
            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {

                String msg = new String(body, "utf-8");
                System.out.println("收到消息:"+msg);

                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }finally {
                    //手动确认消息
                    channel.basicAck(envelope.getDeliveryTag(),false);
                }

            }
        };
 
        boolean autoAck = false;
        channel.basicConsume(QUEUE_NAME,autoAck,consumer);

    }
}

上面的代码会出现问题,尽管消费者1消费一天消息需要等待2秒而消费者2消费一天消息仅需等待1秒。但RabbitMQ还是以消费者1一条消费者2一条的形式发送消息。所以引出如下公平分发代码。

public class WorkQueueConsumerOne {

    private static final String QUEUE_NAME = "test_work_queue";

    public static void main(String[] args) throws IOException, TimeoutException {

        Connection connection = RabbitMQUtil.getConnection();

        final Channel channel = connection.createChannel();
      
        channel.queueDeclare(QUEUE_NAME,false,false,false,null);
        /**
         * 在所有消费者运行channel.basicQos()方法即可进入公平分发 
         * 每个消费者发送消息确认之前,队列不发送新的消息到消费者
         * 消费者一次只处理一个消息
        */
        channel.basicQos(1);

        DefaultConsumer consumer = new DefaultConsumer(channel) {

            @Override
            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {

                String msg = new String(body, "utf-8");
                System.out.println("收到消息:"+msg);

                try {
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }finally {
                    channel.basicAck(envelope.getDeliveryTag(),false);
                }

            }
        };

        boolean autoAck = false;
        channel.basicConsume(QUEUE_NAME,autoAck,consumer);

    }

这样性能优越的消费者就能消费掉更多的消息

发布/订阅模式

先请去如下网址阅读下交换机类型:

https://blog.csdn.net/rainday0310/article/details/22082503

简单的发布/订阅模式将队列bind到交换机上,一个交换机可bind多个队列。生产者发送消息时会将消息推送给所有bind它的队列。然后再由消费者消费。

public class ExchangeProvider {

    private static final String EXCHANGE_NAME = "text_exchange_fanout";

    public static void main(String[] args) throws IOException, TimeoutException {

        Connection connection = RabbitMQUtil.getConnection();
        Channel channel = connection.createChannel();
        //定义exchange  这里定义的exchange类型是'fanout'
        channel.exchangeDeclare(EXCHANGE_NAME, ExchangeTypes.FANOUT);

        String msg = "hello tzh";
        //发送消息 第二个参数是路由 routingKey 这里定义的""
        channel.basicPublish(EXCHANGE_NAME,"",null,msg.getBytes());

        System.out.println("provide : " + msg);

        RabbitMQUtil.close(connection,channel);
    }

}


public class ExchangeConsumerOne {

    private static final String QUEUE_NAME = "text_queue_email";
    private static final String EXCHANGE_NAME = "text_exchange_fanout";

    public static void main(String[] args) throws IOException, TimeoutException {

        Connection connection = RabbitMQUtil.getConnection();
        final Channel channel = connection.createChannel();

        //声明队列
        channel.queueDeclare(QUEUE_NAME,false,false,false,null);
        //将队列与交换机绑定 并声明接收消息的路由
        channel.queueBind(QUEUE_NAME, EXCHANGE_NAME,"");
        channel.basicQos(1);
        DefaultConsumer consumer = new DefaultConsumer(channel) {
            @Override
            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {

                String msg = new String(body, "utf-8");
                System.out.println("consumer two[] :"+msg);
                //这个方法第二个Boolean类型的参数声明是否是多条消息
                channel.basicAck(envelope.getDeliveryTag(),false);
            }
        };

        boolean autoAck = false;
        channel.basicConsume(QUEUE_NAME,autoAck,consumer);

    }
}

public class ExchangerConsumerTwo {

    private static final String QUEUE_NAME = "text_queue_sms";
    private static final String EXCHANGE_NAME = "text_exchange_fanout";

    public static void main(String[] args) throws IOException, TimeoutException {

        Connection connection = RabbitMQUtil.getConnection();
        final Channel channel = connection.createChannel();

        channel.queueDeclare(QUEUE_NAME,false,false,false,null);
        channel.queueBind(QUEUE_NAME, EXCHANGE_NAME,"");

        channel.basicQos(1);

        DefaultConsumer consumer = new DefaultConsumer(channel) {

            @Override
            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {

                String msg = new String(body, "utf-8");
                System.out.println("consumer one[] :"+msg);

                channel.basicAck(envelope.getDeliveryTag(),false);

            }
        };

        boolean autoAck = false;
        channel.basicConsume(QUEUE_NAME,autoAck,consumer);

    }
}

下次总结会做routing 模式和项目中使用较多的topic 模式

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值