【Spring消息】RabbitMq安装及简单应用(二)

前言:

埋头苦写。先把官方文档翻译过来。整个流程跑一遍。上一篇文章,【Spring消息】RabbitMq安装及简单应用(一),把点对点发送消息写完了。之前虽然也可以一个生产者多个消费者,但是一条消息只能被一个消费者处理,所以是点对点。这篇文章来讲讲发布订阅,一对多。一条消息同时被多个消费者(本文称为订阅者)处理。

正文:

一、发布/订阅模式:

引入了一个新概念:Exchange(即上图的X概念)。(其实此概念,在Amqp协议中是必要的一环,暂时可无需理解,后续会提到)可简单先理解为一个路由功能。RabbitMq定义了四种路由模式,direct, topic, headers and fanout.(本文会讲到除headers外其它三种)

1、fanout广播:

由上图可知生产者和队列之间没直接关联关系,甚至不需要知道有这么个东西,所以如果看过上一篇文章的小伙伴可以删掉队列名有关的代码。

1)生产者代码

package com.haibo.future.web.rabbitmq.demo6;

import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import com.rabbitmq.client.MessageProperties;

public class RabbitProduct {
    private final static String EXCHANGE_NAME = "logs";

    public static void main(String[] argv) throws Exception {
        for (int i = 0; i < 20; i++) {
            ConnectionFactory factory = new ConnectionFactory();
            factory.setHost("localhost");
            Connection connection = factory.newConnection();
            Channel channel = connection.createChannel();
            String message = "第"+i+"条"+"Hello World!";
            //本次新增EXCHANGE
            channel.exchangeDeclare(EXCHANGE_NAME, "fanout");
            //发送的时候只需要制定Exchange,不需要制定第二个参数队列名称
            channel.basicPublish(EXCHANGE_NAME, "", null, message.getBytes("UTF-8"));
            System.out.println(" [x] Sent '" + message + "'");
            channel.close();
            connection.close();
        }
    }
}

2)消费者代码

package com.haibo.future.web.rabbitmq.demo6;

import com.rabbitmq.client.*;

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

public class RabbitConsumer {
    private static final String EXCHANGE_NAME = "logs";


    public static void main(String[] argv)
            throws IOException,
            InterruptedException {

        ConnectionFactory factory = new ConnectionFactory();
        factory.setHost("localhost");
        Connection connection = null;
        try {
            connection = factory.newConnection();
        } catch (TimeoutException e) {
            e.printStackTrace();
        }
        final Channel channel = connection.createChannel();
        //定义路由模式广播
        channel.exchangeDeclare(EXCHANGE_NAME, "fanout");
        //消费者需要知道队列名称,因为已知是fanout广播模式,queueName直接从channel定义中获取
        String queueName = channel.queueDeclare().getQueue();
        //将队列和Exchange绑定起来
        channel.queueBind(queueName, EXCHANGE_NAME, "");
        System.out.println(" [*] Waiting for messages. To exit press CTRL+C");
        Consumer consumer = new DefaultConsumer(channel) {
            @Override
            public void handleDelivery(String consumerTag, Envelope envelope,
                                       AMQP.BasicProperties properties, byte[] body)
                    throws IOException {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                String message = new String(body, "UTF-8");
                System.out.println(" [x] Received '" + message + "'");
            }
        };
        boolean autoAck = true;
        channel.basicConsume(queueName, autoAck, consumer);
    }
}

3)测试执行

执行两个消费者,再执行生产者。结果:生产者消息,同时发给了两个消费者。日志略。

2、direct直连:

直连:即binding Key全匹配。上图中Binding Key即black。

1)、生产者:(不与队列直接关联,绑定binding Key)

package com.haibo.future.web.rabbitmq.demo7;

import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;

public class RabbitProduct {
    private final static String EXCHANGE_NAME = "logs2";

    public static void main(String[] argv) throws Exception {
        for (int i = 0; i < 20; i++) {
            ConnectionFactory factory = new ConnectionFactory();
            factory.setHost("localhost");
            Connection connection = factory.newConnection();
            Channel channel = connection.createChannel();
            String message = "第"+i+"条"+"Hello World!";;
            //本次新增EXCHANGE:direct直接匹配,全匹配模式
            channel.exchangeDeclare(EXCHANGE_NAME, "direct");
            //发送的时候只需要制定Exchange,不需要制定第二个参数队列名称/此处是drect模式,第二个参数为binding key
            channel.basicPublish(EXCHANGE_NAME, "black", null, message.getBytes("UTF-8"));
            System.out.println(" [x] Sent '" + message + "'");
            channel.close();
            connection.close();
        }
    }
}

2)、消费者1(与队列直接关联,绑定binding Key "black")

package com.haibo.future.web.rabbitmq.demo7;

import com.rabbitmq.client.*;

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

public class RabbitConsumer {
    private static final String EXCHANGE_NAME = "logs2";

    public static void main(String[] argv)
            throws IOException,
            InterruptedException {

        ConnectionFactory factory = new ConnectionFactory();
        factory.setHost("localhost");
        Connection connection = null;
        try {
            connection = factory.newConnection();
        } catch (TimeoutException e) {
            e.printStackTrace();
        }
        final Channel channel = connection.createChannel();
        //定义路由模式direct
        channel.exchangeDeclare(EXCHANGE_NAME, "direct");
        //消费者需要知道队列名称,因为已知是direct模式,queueName直接从channel定义中获取
        String queueName = channel.queueDeclare().getQueue();
        //将队列和Exchange绑定起来
        channel.queueBind(queueName, EXCHANGE_NAME, "black");
        System.out.println(" [*] Waiting for messages. To exit press CTRL+C");
        Consumer consumer = new DefaultConsumer(channel) {
            @Override
            public void handleDelivery(String consumerTag, Envelope envelope,
                                       AMQP.BasicProperties properties, byte[] body)
                    throws IOException {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                String message = new String(body, "UTF-8");
                System.out.println(" [x] Received '" + message + "'");
            }
        };
        boolean autoAck = true;
        channel.basicConsume(queueName, autoAck, consumer);
    }
}

3)、消费者2(与队列直接关联,绑定binding Key "red")

package com.haibo.future.web.rabbitmq.demo7;

import com.rabbitmq.client.*;

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

public class RabbitConsumer2 {
    private static final String EXCHANGE_NAME = "logs2";


    public static void main(String[] argv)
            throws IOException,
            InterruptedException {

        ConnectionFactory factory = new ConnectionFactory();
        factory.setHost("localhost");
        Connection connection = null;
        try {
            connection = factory.newConnection();
        } catch (TimeoutException e) {
            e.printStackTrace();
        }
        final Channel channel = connection.createChannel();
        //定义路由模式direct
        channel.exchangeDeclare(EXCHANGE_NAME, "direct");
        //消费者需要知道队列名称,因为已知是direct模式,queueName直接从channel定义中获取
        String queueName = channel.queueDeclare().getQueue();
        //将队列和Exchange绑定起来,binding key 为black
        channel.queueBind(queueName, EXCHANGE_NAME, "red");
        System.out.println(" [*] Waiting for messages. To exit press CTRL+C");
        Consumer consumer = new DefaultConsumer(channel) {
            @Override
            public void handleDelivery(String consumerTag, Envelope envelope,
                                       AMQP.BasicProperties properties, byte[] body)
                    throws IOException {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                String message = new String(body, "UTF-8");
                System.out.println(" [x] Received '" + message + "'");
            }
        };
        boolean autoAck = true;
        channel.basicConsume(queueName, autoAck, consumer);
    }
}

4)、消费者3(与队列直接关联,绑定binding Key "black")

package com.haibo.future.web.rabbitmq.demo7;

import com.rabbitmq.client.*;

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

public class RabbitConsumer3 {
    private static final String EXCHANGE_NAME = "logs2";


    public static void main(String[] argv)
            throws IOException,
            InterruptedException {

        ConnectionFactory factory = new ConnectionFactory();
        factory.setHost("localhost");
        Connection connection = null;
        try {
            connection = factory.newConnection();
        } catch (TimeoutException e) {
            e.printStackTrace();
        }
        final Channel channel = connection.createChannel();
        //定义路由模式direct
        channel.exchangeDeclare(EXCHANGE_NAME, "direct");
        //消费者需要知道队列名称,因为已知是direct模式,queueName直接从channel定义中获取
        String queueName = channel.queueDeclare().getQueue();
        //将队列和Exchange绑定起来,binding key 为black
        channel.queueBind(queueName, EXCHANGE_NAME, "black");
        System.out.println(" [*] Waiting for messages. To exit press CTRL+C");
        Consumer consumer = new DefaultConsumer(channel) {
            @Override
            public void handleDelivery(String consumerTag, Envelope envelope,
                                       AMQP.BasicProperties properties, byte[] body)
                    throws IOException {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                String message = new String(body, "UTF-8");
                System.out.println(" [x] Received '" + message + "'");
            }
        };
        boolean autoAck = true;
        channel.basicConsume(queueName, autoAck, consumer);
    }
}

5)、执行测试:

3个消费者启动,启动生产者。日志显示:消费者1、消费者3显示收到生产者的消息,消费者2不能收到生产者的消息。日志略。

3、Topic主题:

直接上代码:

1)、消费者1:(rootingKey是*.orange.rabbit)

package com.haibo.future.web.rabbitmq.demo8;

import com.rabbitmq.client.*;

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

public class RabbitConsumer {
    private static final String EXCHANGE_NAME = "topic_logs";

    public static void main(String[] argv)
            throws IOException,
            InterruptedException {

        ConnectionFactory factory = new ConnectionFactory();
        factory.setHost("localhost");
        Connection connection = null;
        try {
            connection = factory.newConnection();
        } catch (TimeoutException e) {
            e.printStackTrace();
        }
        final Channel channel = connection.createChannel();
        //定义路由模式direct
        channel.exchangeDeclare(EXCHANGE_NAME, "topic");
        //消费者需要知道队列名称,因为已知是direct模式,queueName直接从channel定义中获取
        String queueName = channel.queueDeclare().getQueue();
        //将队列和Exchange绑定起来
        channel.queueBind(queueName, EXCHANGE_NAME, "*.orange.rabbit");
        System.out.println(" [*] Waiting for messages. To exit press CTRL+C");
        Consumer consumer = new DefaultConsumer(channel) {
            @Override
            public void handleDelivery(String consumerTag, Envelope envelope,
                                       AMQP.BasicProperties properties, byte[] body)
                    throws IOException {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                String message = new String(body, "UTF-8");
                System.out.println(" [x] Received '" + message + "'");
            }
        };
        boolean autoAck = true;
        channel.basicConsume(queueName, autoAck, consumer);
    }
}

2)、消费者2:(rooting key 是 *.orange.bird)

package com.haibo.future.web.rabbitmq.demo8;

import com.rabbitmq.client.*;

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

public class RabbitConsumer2 {
    private static final String EXCHANGE_NAME = "topic_logs";

    public static void main(String[] argv)
            throws IOException,
            InterruptedException {

        ConnectionFactory factory = new ConnectionFactory();
        factory.setHost("localhost");
        Connection connection = null;
        try {
            connection = factory.newConnection();
        } catch (TimeoutException e) {
            e.printStackTrace();
        }
        final Channel channel = connection.createChannel();
        //定义路由模式direct
        channel.exchangeDeclare(EXCHANGE_NAME, "topic");
        //消费者需要知道队列名称,因为已知是direct模式,queueName直接从channel定义中获取
        String queueName = channel.queueDeclare().getQueue();
        //将队列和Exchange绑定起来
        channel.queueBind(queueName, EXCHANGE_NAME, "*.orange.bird");
        System.out.println(" [*] Waiting for messages. To exit press CTRL+C");
        Consumer consumer = new DefaultConsumer(channel) {
            @Override
            public void handleDelivery(String consumerTag, Envelope envelope,
                                       AMQP.BasicProperties properties, byte[] body)
                    throws IOException {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                String message = new String(body, "UTF-8");
                System.out.println(" [x] Received '" + message + "'");
            }
        };
        boolean autoAck = true;
        channel.basicConsume(queueName, autoAck, consumer);
    }
}

3)、消费者3:(rooting key是lazy.#)

package com.haibo.future.web.rabbitmq.demo8;

import com.rabbitmq.client.*;

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

public class RabbitConsumer3 {
    private static final String EXCHANGE_NAME = "topic_logs";

    public static void main(String[] argv)
            throws IOException,
            InterruptedException {

        ConnectionFactory factory = new ConnectionFactory();
        factory.setHost("localhost");
        Connection connection = null;
        try {
            connection = factory.newConnection();
        } catch (TimeoutException e) {
            e.printStackTrace();
        }
        final Channel channel = connection.createChannel();
        //定义路由模式direct
        channel.exchangeDeclare(EXCHANGE_NAME, "topic");
        //消费者需要知道队列名称,因为已知是direct模式,queueName直接从channel定义中获取
        String queueName = channel.queueDeclare().getQueue();
        //将队列和Exchange绑定起来
        channel.queueBind(queueName, EXCHANGE_NAME, "lazy.#");
        System.out.println(" [*] Waiting for messages. To exit press CTRL+C");
        Consumer consumer = new DefaultConsumer(channel) {
            @Override
            public void handleDelivery(String consumerTag, Envelope envelope,
                                       AMQP.BasicProperties properties, byte[] body)
                    throws IOException {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                String message = new String(body, "UTF-8");
                System.out.println(" [x] Received '" + message + "'");
            }
        };
        boolean autoAck = true;
        channel.basicConsume(queueName, autoAck, consumer);
    }
}

4)、生产者:

package com.haibo.future.web.rabbitmq.demo8;

import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;

public class RabbitProduct {
    private static final String EXCHANGE_NAME = "topic_logs";

    public static void main(String[] argv) throws Exception {
        for (int i = 0; i < 10; i++) {
            ConnectionFactory factory = new ConnectionFactory();
            factory.setHost("localhost");
            Connection connection = factory.newConnection();
            Channel channel = connection.createChannel();
            String message = null;
            //P-->X :本次新增EXCHANGE:direct直接匹配,全匹配模式
            channel.exchangeDeclare(EXCHANGE_NAME, "topic");
            //X-->Q :发送的时候只需要制定Exchange,不需要制定第二个参数队列名称/此处是drect模式,第二个参数为binding key/此处是topic模式,第二个参数为rooting key
            if (i == 5) {
                message = "第" + i + "条:" + "lazy.orange.rabbit" + i;
                channel.basicPublish(EXCHANGE_NAME, "lazy.orange.rabbit" + i, null, message.getBytes("UTF-8"));
            } else {
                if (i % 2 == 1) {
                    message = "第" + i + "条:" + i + ".orange." + "rabbit";
                    channel.basicPublish(EXCHANGE_NAME, i + ".orange." + "rabbit", null, message.getBytes("UTF-8"));
                } else {
                    message = "第" + i + "条:" + i + ".orange." + "bird";
                    channel.basicPublish(EXCHANGE_NAME, i + ".orange." + "bird", null, message.getBytes("UTF-8"));
                }
            }
            System.out.println(" [x] Sent '" + message + "'");
            channel.close();
            connection.close();
        }
    }
}

5)、执行测试:

消费者1,2,3分别执行,执行生产者。结果如下:

生产者:

[x] Sent '第0条:0.orange.bird'
 [x] Sent '第1条:1.orange.rabbit'
 [x] Sent '第2条:2.orange.bird'
 [x] Sent '第3条:3.orange.rabbit'
 [x] Sent '第4条:4.orange.bird'
 [x] Sent '第5条:lazy.orange.rabbit5'
 [x] Sent '第6条:6.orange.bird'
 [x] Sent '第7条:7.orange.rabbit'
 [x] Sent '第8条:8.orange.bird'
 [x] Sent '第9条:9.orange.rabbit'

消费者1:(rootingKey是*.orange.rabbit)

[*] Waiting for messages. To exit press CTRL+C
 [x] Received '第1条:1.orange.rabbit'
 [x] Received '第3条:3.orange.rabbit'
 [x] Received '第7条:7.orange.rabbit'
 [x] Received '第9条:9.orange.rabbit'

消费者2:(rooting key 是 *.orange.bird)

[*] Waiting for messages. To exit press CTRL+C
 [x] Received '第0条:0.orange.bird'
 [x] Received '第2条:2.orange.bird'
 [x] Received '第4条:4.orange.bird'
 [x] Received '第6条:6.orange.bird'
 [x] Received '第8条:8.orange.bird'

消费者3:(rooting key是lazy.#)

[*] Waiting for messages. To exit press CTRL+C
 [x] Received '第5条:lazy.orange.rabbit5'

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值