rabbitmq模式

Rabbitmq的几种工作模式

  1. 简单模式 HelloWorld
  2. 工作队列模式 Work Queue
  3. 发布订阅模式 Publish/subscribe
  4. 路由模式 Routing
  5. 通配符模式 Topic
  6. rpc
  7. publisher confirms
    先记录一下前5种,不整合spring
    首先创建虚拟机VirtualHost,虚拟机可以理解为数据库,每个虚拟机之间是隔离的,消息不能相互传递


    image.png

    image.png

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

public class RabbitUtils {
    private static ConnectionFactory connectionFactory = new ConnectionFactory ();

    static {
        //创建链接
        connectionFactory.setHost ("192.168.137.129");
        connectionFactory.setPort (5672);
        connectionFactory.setUsername ("duoduo");
        connectionFactory.setPassword ("duoduo");
        connectionFactory.setVirtualHost ("/duoduo");
    }

    public static Connection getConnection() {
        Connection conn = null;
        try {
            conn = connectionFactory.newConnection ();
            return conn;
        } catch (Exception e) {
            throw new RuntimeException (e);
        }
    }
}

简单模式一个生产者一个消费者,不需要创建exchange (交换机),会默认创建一个交换机
生产者

public class Producer {

    public static void main(String[] args) throws IOException, TimeoutException {
        //获取TCP长连接
        Connection conn = RabbitUtils.getConnection();
        //创建通信“通道”,相当于TCP中的虚拟连接
        Channel channel = conn.createChannel();
        //创建队列,声明并创建一个队列,如果队列已存在,则使用这个队列
        //第一个参数:队列名称ID
        //第二个参数:是否持久化,false对应不持久化数据,MQ停掉数据就会丢失
        //第三个参数:是否队列私有化,false则代表所有消费者都可以访问,true代表只有第一次拥有它的消费者才能一直使用,其他消费者不让访问
        //第四个:是否自动删除,false代表连接停掉后不自动删除掉这个队列
        //其他额外的参数, null
        channel.queueDeclare("helloworld",false, false, false, null);
        String message = "helloworldRabbitMq";
        //四个参数
        //exchange 交换机,暂时用不到,在后面进行发布订阅时才会用到
        //队列名称
        //额外的设置属性
        //最后一个参数是要传递的消息字节数组
        channel.basicPublish("", "helloworld", null,message.getBytes());
        channel.close();
        conn.close();
        System.out.println("===发送成功===");
    }
}

消费者

public class Consumer {

    public static void main(String[] args) throws IOException, TimeoutException {
        //获取TCP长连接
        Connection conn = RabbitUtils.getConnection ();
        //创建通道
         Channel channel = conn.createChannel ();
        //创建队列,声明并创建一个队列,如果队列已存在,则使用这个队列
        //第一个参数:队列名称ID
        //第二个参数:是否持久化,false对应不持久化数据,MQ停掉数据就会丢失
        //第三个参数:是否队列私有化,false则代表所有消费者都可以访问,true代表只有第一次拥有它的消费者才能一直使用,其他消费者不让访问
        //第四个:是否自动删除,false代表连接停掉后不自动删除掉这个队列
        //其他额外的参数, null
        channel.queueDeclare ("helloworld", false, false, false, null);
        //从MQ服务器中获取数据
        //创建一个消息消费者
        //第一个参数:队列名
        //第二个参数代表是否自动确认收到消息,false代表手动编程来确认消息,这是MQ的推荐做法
        //第三个参数要传入DefaultConsumer的实现类
        channel.basicConsume ("helloworld", false, new DefaultConsumer (channel){
            @Override
            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
                String message = new String (body);
                System.out.println ("消费者接收到的消息:" + message);
                //每生产一个消息自增1,作为消息的id,保证消息不被重复的消费
                System.out.println ("消息的TagId:" + envelope.getDeliveryTag ());
                //false只确认签收当前的消息,设置为true的时候则代表签收该消费者所有未签收的消息
                Channel _channel = super.getChannel ();
                //将消息的id确定为已经消费,后续会分析如何保证消息不丢失和不重复消费消息
                _channel.basicAck (envelope.getDeliveryTag (), false);
            }
        });
    }
}

WorkQueue工作队列模式,一个生产者多个消费者,因为消费的是同一个队列,所以消费者之间是竞争关系,不用exchange,底层会有默认的交换机
和上一个模式是一样的,只不过多个客户端同时绑定同一个队列
客户端轮询的消费队列里面的消息,ABC三个客户端,共有90个消息,C服务器的性能不好,消费的时间长一点,但是ABC三个客户端每个都会消费30个消息
这里可以用channel.basicQos(1);消费完消息之后从队列马上取一条新消息
A的性能最好再B再C,使用channel.basicQos(1);这段代码之后A可能消费60条消息 B消费20条C只消费了10条


image.png

发布订阅模式 Publish/Subscribe
需要将交换机的类型定义为fanout,并将交换机和队列进行绑定,不需要设定routing key,生产者将消息发送给交换机,由交换机将消息发送给绑定的队列,再由消费者获取消息.


image.png

生产者
public class Producer {


    public static void main(String[] args) throws Exception {
        Connection connection = RabbitUtils.getConnection ();
        Channel channel = connection.createChannel ();
        String message = "发布订阅模式";
        //定义了交换机,交换机是要事先创建好,如果是spring可以用程序取初始化,这里我们用页面的方式创建,发布订阅模式的交换机的模式要选择fanout
//第一个参数为交换机 第二个参数为routingkey,因为是发布订阅模式,不需要定义,第三个参数要发送的消息
        for (int i = 0; i < 10; i++) {
            channel.basicPublish ("fanoutTest", "", null, message.getBytes ());
        }
        channel.close ();
        connection.close ();
    }
}

两个消费者

public class Consumers {
    public static void main(String[] args) throws IOException {
        //获取TCP长连接
        Connection connection = RabbitUtils.getConnection ();
        //获取虚拟连接
        final Channel channel = connection.createChannel ();
        //声明队列信息
        channel.queueDeclare ("pubsub", false, false, false, null);
        //queueBind用于将队列与交换机绑定
        //参数1:队列名 参数2:交互机名  参数三:routing key 因为是发布订阅模式,不是要路由key
        channel.queueBind ("pubsub", "fanoutTest", "");
        channel.basicQos (1);
        channel.basicConsume ("pubsub", false, new DefaultConsumer (channel) {
            @Override
            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
                System.out.println ("接收消息:" + new String (body));
                channel.basicAck (envelope.getDeliveryTag (), false);
            }
        });
    }
}
public class Consumer1 {
    public static void main(String[] args) throws IOException {
        //获取TCP长连接
        Connection connection = RabbitUtils.getConnection ();
        //获取虚拟连接
        final Channel channel = connection.createChannel ();
        //声明队列信息
        channel.queueDeclare ("pubsub1", false, false, false, null);
        //queueBind用于将队列与交换机绑定
        //参数1:队列名 参数2:交互机名  参数三:routing key 因为是发布订阅模式,不是要路由key
        channel.queueBind ("pubsub1", "fanoutTest", "");
        channel.basicQos (1);
        channel.basicConsume ("pubsub1", false, new DefaultConsumer (channel) {
            @Override
            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
                System.out.println ("接收消息:" + new String (body));
                channel.basicAck (envelope.getDeliveryTag (), false);
            }
        });
    }
}

可以发现queueBind方法将两个队列同时绑定了同一个交换机,并且没有声明路由key,发布订阅模式不需要定义路由key,当生产者发布消息的时候,首先发送给交换机,由交换机同时转发给两个队列,保证两个消费者都能获取到

路由模式 Routing
需要设置类型为 direct 的交换机,交换机和队列进行绑定,并且指定 routing key,当发送消息到交换机后,交换机会根据 routing key 将消息发送到对应的队列。这里是routing key精确匹配
首先创建模式为direct模式的交换机
生产者

public class Producer {
    public static void main(String[] args) throws Exception {
        Map stringStringMap = new HashMap ();
        stringStringMap.put("routing","路由模式");
        stringStringMap.put("routing1","路由模式1");
        Connection connection = RabbitUtils.getConnection ();
        Channel channel = connection.createChannel ();
        for (Map.Entry stringStringEntry : stringStringMap.entrySet ()) {
            //路由模式定义了路由key,这里将map的key作为路由key
            channel.basicPublish ("directTest",stringStringEntry.getKey () , null, stringStringEntry.getValue ().getBytes ());
        }
        channel.close ();
        connection.close ();
    }
}

消费者

public class Consumers {
    public static void main(String[] args) throws IOException {
        //获取TCP长连接
        Connection connection = RabbitUtils.getConnection ();
        //获取虚拟连接
        final Channel channel = connection.createChannel ();
        //声明队列信息
        channel.queueDeclare ("routing", false, false, false, null);
        //第三个参数为路由key,路由模式是路由key要精确匹配
        channel.queueBind ("routing", "directTest", "routing");
        channel.basicQos (1);
        channel.basicConsume ("routing", false, new DefaultConsumer (channel) {
            @Override
            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
                System.out.println ("接收消息:" + new String (body));
                channel.basicAck (envelope.getDeliveryTag (), false);
            }
        });
    }
}


public class Consumer1 {
    public static void main(String[] args) throws IOException {
        //获取TCP长连接
        Connection connection = RabbitUtils.getConnection ();
        //获取虚拟连接
        final Channel channel = connection.createChannel ();
        //声明队列信息
        channel.queueDeclare ("routing1", false, false, false, null);
        //第三个参数为路由key,路由模式是路由key要精确匹配
        channel.queueBind ("routing1", "directTest", "routing1");
        channel.basicQos (1);
        channel.basicConsume ("routing1", false, new DefaultConsumer (channel) {
            @Override
            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
                System.out.println ("接收消息:" + new String (body));
                channel.basicAck (envelope.getDeliveryTag (), false);
            }
        });
    }
}

通配符模式 Topic
需要设置类型为 topic 的交换机,交换机和队列进行绑定,并且指定通配符方式的 routing key,当发送消息到交换机后,交换机会根据 routing key 将消息发送到对应的队列。利用通配符的方式发送到不同的队列
通配符的#和的区别,可以上网找找资料,其实只能代表匹配一个单词,#可以代表多个单词

生产者

public class Producer {
    public static void main(String[] args) throws Exception {
        Map stringStringMap = new HashMap ();
        stringStringMap.put("a.b.c.d","通配符模式a.b.c.d");
        stringStringMap.put("1.2.3.d","通配符模式1.2.3.d");
        Connection connection = RabbitUtils.getConnection ();
        Channel channel = connection.createChannel ();
        for (Map.Entry stringStringEntry : stringStringMap.entrySet ()) {
            //路由模式定义了路由key,这里将map的key作为路由key
            channel.basicPublish ("topicTest",stringStringEntry.getKey () , null, stringStringEntry.getValue ().getBytes ());
        }
        channel.close ();
        connection.close ();
    }
}

消费者

public class Consumers {
    public static void main(String[] args) throws IOException {
        //获取TCP长连接
        Connection connection = RabbitUtils.getConnection ();
        //获取虚拟连接
        final Channel channel = connection.createChannel ();
        //声明队列信息
        channel.queueDeclare ("topic", false, false, false, null);
        //第三个参数为路由key,主题模式是路由key模糊匹配,#匹配多个单词
        channel.queueBind ("topic", "topicTest", "#.d");
        channel.basicQos (1);
        channel.basicConsume ("topic", false, new DefaultConsumer (channel) {
            @Override
            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
                System.out.println ("接收消息:" + new String (body));
                channel.basicAck (envelope.getDeliveryTag (), false);
            }
        });
    }
}

public class Consumer1 {
    public static void main(String[] args) throws IOException {
        //获取TCP长连接
        Connection connection = RabbitUtils.getConnection ();
        //获取虚拟连接
        final Channel channel = connection.createChannel ();
        //声明队列信息
        channel.queueDeclare ("topic1", false, false, false, null);
        //第三个参数为路由key,主题模式是路由key模糊匹配,*代表匹配一个单词
        channel.queueBind ("topic1", "topicTest", "*.*.*.d");
        channel.basicQos (1);
        channel.basicConsume ("topic1", false, new DefaultConsumer (channel) {
            @Override
            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
                System.out.println ("接收消息:" + new String (body));
                channel.basicAck (envelope.getDeliveryTag (), false);
            }
        });
    }
}

得到的结果两个消费者都能消费到两个消息
接收消息:通配符模式a.b.c.d
接收消息:通配符模式1.2.3.d
也就是 ..*.d能同时匹配 a.b.c.d 1.2.3.d
同事#.d也能同时匹配a.b.c.d 1.2.3.d

你可能感兴趣的:(rabbitmq模式)