RabbitMq教程

 测试代码Github地址:https://github.com/zhouyanger/java_demo/tree/master/rabbitmq-java

一.什么是MQ

      MQ全称为Message Queue, 消息队列(MQ)是一种应用程序对应用程序的通信方法。MQ是消费-生产者模型的一个典型的代表,一端往消息队列中不断写入消息,而另一端则可以读取队列中的消息。

他能做什么?

 

java rabbitmq学习 rabbitmq详细教程_持久化

 

 

 

      RabbitMQ是MQ的一种。下面详细介绍一下RabbitMQ的基本概念。

      1、队列、生产者、消费者

      队列是RabbitMQ的内部对象,用于存储消息。生产者(下图中的P)生产消息并投递到队列中,消费者(下图中的C)可以从队列中获取消息并消费。

      

java rabbitmq学习 rabbitmq详细教程_java rabbitmq学习_02

 

 

 

      多个消费者可以订阅同一个队列,这时队列中的消息会被平均分摊给多个消费者进行处理,而不是每个消费者都收到所有的消息并处理。

    

java rabbitmq学习 rabbitmq详细教程_数据_03

 

 

 

 

2、Exchange、Binding

      刚才我们看到生产者将消息投递到队列中,实际上这在RabbitMQ中这种事情永远都不会发生。实际的情况是,生产者将消息发送到Exchange(交换器,下图中的X),再通过Binding将Exchange与Queue关联起来。

      

java rabbitmq学习 rabbitmq详细教程_持久化_04

 

 

 

3、Exchange Type、Bingding key、routing key

      消费者在绑定(Binding)Exchange与Queue的同时,一般会指定一个binding key。在绑定多个Queue到同一个Exchange的时候,这些Binding允许使用相同的binding key。

      生产者在将消息发送给Exchange的时候,一般会指定一个routing key,来指定这个消息的路由规则,生产者就可以在发送消息给Exchange时,通过指定routing key来决定消息流向哪些队列。

      RabbitMQ常用的Exchange Type有三种: direct、fanout、topic、Header

l  direct:把消息投递到那些binding key与routing key完全匹配的队列中。

l  fanout:把所有发送到该Exchange的消息投递到所有与它绑定的队列中。

l  topic:将消息路由到binding key与routing key模式匹配的队列中。

      附上一张RabbitMQ的结构图:

      

java rabbitmq学习 rabbitmq详细教程_持久化_05

 

 

    

最后来具体解析一下几个问题:

1、可以自动创建队列,也可以手动创建队列,如果自动创建队列,那么是谁负责创建队列呢?是生产者?还是消费者? 

      如果队列不存在,当然消费者不会收到任何的消息。但是如果队列不存在,那么生产者发送的消息就会丢失。所以,为了数据不丢失,消费者和生产者都可以创建队列。那么如果创建一个已经存在的队列呢?那么不会有任何的影响。需要注意的是没有任何的影响,也就是说第二次创建如果参数和第一次不一样,那么该操作虽然成功,但是队列属性并不会改变。

      队列对于负载均衡的处理是完美的。对于多个消费者来说,RabbitMQ使用轮询的方式均衡的发送给不同的消费者。

2. RabbitMQ 为什么需要信道?为什么不是 TCP 直接通信?

#. Channel 中文叫做信道,是 TCP 里面的虚拟链接。例如:电缆相当于 TCP,信道是

一个独立光纤束,一条 TCP 连接上创建多条信道是没有问题的。

#TCP 的创建和销毁开销特别大。创建需要 3 次握手,销毁需要 4 次分手。

#. 如果不用信道,那应用程序就会以 TCP 链接 Rabbit,高峰时每秒成千上万条链接

会造成资源巨大的浪费,而且操作系统每秒处理 TCP 链接数也是有限制的,必定造成性能

瓶颈。

#. 信道的原理是一条线程一条通道,多条线程多条通道同用一条 TCP 链接。一条 TCP

链接可以容纳无限的信道,即使每秒成千上万的请求也不会成为性能的瓶颈。

3、RabbitMQ的消息确认机制

      默认情况下,如果消息已经被某个消费者正确的接收到了,那么该消息就会被从队列中移除。当然也可以让同一个消息发送到很多的消费者。

      如果一个队列没有消费者,那么,如果这个队列有数据到达,那么这个数据会被缓存,不会被丢弃。当有消费者时,这个数据会被立即发送到这个消费者,这个数据被消费者正确收到时,这个数据就被从队列中删除。

可以将消息进行持久化。要将消息持久化,前提是:队列、Exchange都持久化

     那么什么是正确收到呢?通过ack。每个消息都要被acknowledged(确认,ack)。我们可以显示的在程序中去ack,也可以自动的ack。如果有数据没有被ack,那么:

     RabbitMQ Server会把这个信息发送到下一个消费者。

     如果这个app有bug,忘记了ack,那么RabbitMQServer不会再发送数据给它,因为Server认为这个消费者处理能力有限。

而且ack的机制可以起到限流的作用(Benefitto throttling):在消费者处理完成数据后发送ack,甚至在额外的延时后发送ack,将有效的均衡消费者的负载。

 

二.Java中使用rabbitmq

Rabbitmq有几种类型的交换机。direct、fanout、topic、header等等,下面就这几种分别测试。

2.1先来写一个不指定交换机的测试,(其实是有只是rabbitmq默认的交换机)

1)新建两个项目,rabbitmq-producer和rabbitmq-consumer的maven工程,都导入下面jar

<dependency>
    <groupId>com.rabbitmq</groupId>
    <artifactId>amqp-client</artifactId>
    <version>4.0.3</version>
</dependency>
<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-simple</artifactId>
    <version>1.7.25</version>
    <scope>compile</scope>
</dependency>

2)生产方producer代码

public class ProduceTest {

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

        ConnectionFactory connectionFactory = new ConnectionFactory();

        connectionFactory.setHost("127.0.0.1");

        connectionFactory.setPort(5672);

        connectionFactory.setUsername("guest");

        connectionFactory.setPassword("guest");

        connectionFactory.setVirtualHost("/");//rabbitmq默认虚拟机名称为“/”,虚拟机相当于一个独立的mq服

        Connection connection = null;

        Channel channel = null;

        try {

            //创建与RabbitMQ服务的TCP连接 

             connection = connectionFactory.newConnection();

            channel = connection.createChannel();

            

            //默认交换器

            String queue_name = "queue_test";

             for (int i=0;i<10;i++) {

                 String message = "消息》》" + i;

                 /**

                  * 消息发布方法 

                  * param1:Exchange的名称,如果没有指定,则使用Default Exchange 

                  * param2:routingKey,消息的路由Key,是用于Exchange(交换机)将消息转发到指定的消息队列 ,默认交换机的key是队列名

                  * param3:消息包含的属性 

                  * param4:消息体 

                  * */

                  channel.basicPublish("",queue_name,null,message.getBytes());   


             }
}catch (Exception e){

            e.printStackTrace();

        }finally {

            if (channel!=null){

                channel.close();

            }

            if(connection!=null){

                connection.close();

            }

        }

    }

}

3)消费方

public class ConsumerTest {

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

        ConnectionFactory connectionFactory = new ConnectionFactory();

        connectionFactory.setHost("127.0.0.1");

        connectionFactory.setPort(5672);

        connectionFactory.setUsername("guest");

        connectionFactory.setPassword("guest");

        connectionFactory.setVirtualHost("/");//rabbitmq默认虚拟机名称为“/”,虚拟机相当于一个独立的mq服

        Connection connection = connectionFactory.newConnection();

        Channel channel = connection.createChannel();

        

        //使用默认交换器

        String queue_name = "queue_test";

        /**

         * 声明队列,如果Rabbit中没有此队列将自动创建 

         * param1:队列名称 

         * param2:是否持久化 

         * param3:队列是否独占此连接 

         * param4:队列不再使用时是否自动删除此队列 

         * param5:队列参数 

         */

        channel.queueDeclare(queue_name,true,false,false,null);

        /**

         * 监听队列String queue, boolean autoAck,Consumer callback 

         * 参数明细 

         * 1、队列名称 

         * 2、是否自动回复,设置为true为表示消息接收到自动向mq回复接收到了,mq接收到回复会删除消息,设置 

         为false则需要手动回复 

         * 3、消费消息的方法,消费者接收到消息后调用此方法 

         */


        channel.basicConsume(queue_name,true,new DefaultConsumer(channel){

            @Override

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

                System.out.println(new String(body,"utf-8"));

        }

        });

}

4)测试,运行生产方,再运行消费方

 

java rabbitmq学习 rabbitmq详细教程_数据_06

 

 

总结:

#生产方操作流程

 创建连接》创建通道》声明交换机》发送消息

#消费方操作流程

创建连接》创建通道》声明交换机》声明队列》绑定

2.2 Direct Exchange(发布于订阅,完全匹配)

,完全匹配路由key,binding key和routing key必须完全一致才能接收消息

 

java rabbitmq学习 rabbitmq详细教程_TCP_07

 

 

#生产方代码

public class ProduceTest {

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

        ConnectionFactory connectionFactory = new ConnectionFactory();

        connectionFactory.setHost("127.0.0.1");

        connectionFactory.setPort(5672);

        connectionFactory.setUsername("guest");

        connectionFactory.setPassword("guest");

        connectionFactory.setVirtualHost("/");//rabbitmq默认虚拟机名称为“/”,虚拟机相当于一个独立的mq服

        Connection connection = null;

        Channel channel = null;

        try {

            //创建与RabbitMQ服务的TCP连接 

             connection = connectionFactory.newConnection();

            channel = connection.createChannel();
//direct交换机
String directExchangeName = "direct_exchange_inform";

String directQqRoutKey = "direct_qq_key";

 String directMessage = "direct消息";
//声明交换机
channel.exchangeDeclare(directExchangeName,BuiltinExchangeType.DIRECT);
//发布消息
channel.basicPublish(directExchangeName,directQqRoutKey,null,directMessage.getBytes());
}catch (Exception e){

            e.printStackTrace();

        }finally {

            if (channel!=null){

                channel.close();

            }

            if(connection!=null){

                connection.close();

            }

        }

    }

}


#消费方代码

public class ConsumerTest {

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

        ConnectionFactory connectionFactory = new ConnectionFactory();

        connectionFactory.setHost("127.0.0.1");

        connectionFactory.setPort(5672);

        connectionFactory.setUsername("guest");

        connectionFactory.setPassword("guest");

        connectionFactory.setVirtualHost("/");//rabbitmq默认虚拟机名称为“/”,虚拟机相当于一个独立的mq服

        Connection connection = connectionFactory.newConnection();

        Channel channel = connection.createChannel();
//direct交换器
String directExchangexchangeName = "direct_exchange_inform";

String directQqQueueName = "direct_qq_queue";

String directQqRoutKey = "direct_qq_key";
//表示声明了qq队列
channel.queueDeclare(directQqQueueName,true,false,false,null);
//建立一个绑定关系
channel.queueBind(directQqQueueName,directExchangexchangeName,directQqRoutKey,null);

channel.basicConsume(directQqQueueName,true,new DefaultConsumer(channel){

    @Override

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

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

    }

});
}

}


 

2.3 Fanout Exchange(广播)

不设置路由键,只需要简单的将队列绑定到交换机上;发送到交换机的消息都会被转发到与该交换机绑定的所有队列上

 

java rabbitmq学习 rabbitmq详细教程_持久化_08

 

 

#生产方代码

public class ProduceTest {

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

        ConnectionFactory connectionFactory = new ConnectionFactory();

        connectionFactory.setHost("127.0.0.1");

        connectionFactory.setPort(5672);

        connectionFactory.setUsername("guest");

        connectionFactory.setPassword("guest");

        connectionFactory.setVirtualHost("/");//rabbitmq默认虚拟机名称为“/”,虚拟机相当于一个独立的mq服

        Connection connection = null;

        Channel channel = null;

        try {

            //创建与RabbitMQ服务的TCP连接 

             connection = connectionFactory.newConnection();

            channel = connection.createChannel();
//fanout
String fanoutExchangeName = "exchange_fanout_inform";
//路由键为空

 String fanoutRoutKey = "";

 String fanoutMessage = "fanout消息";

channel.exchangeDeclare(fanoutExchangeName,BuiltinExchangeType.FANOUT);

channel.basicPublish(fanoutExchangeName,fanoutRoutKey,null,fanoutMessage.getBytes());
}catch (Exception e){

            e.printStackTrace();

        }finally {

            if (channel!=null){

                channel.close();

            }

            if(connection!=null){

                connection.close();

            }

        }

    }

}


#消费方代码

public class ConsumerTest {

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

        ConnectionFactory connectionFactory = new ConnectionFactory();

        connectionFactory.setHost("127.0.0.1");

        connectionFactory.setPort(5672);

        connectionFactory.setUsername("guest");

        connectionFactory.setPassword("guest");

        connectionFactory.setVirtualHost("/");//rabbitmq默认虚拟机名称为“/”,虚拟机相当于一个独立的mq服

        Connection connection = connectionFactory.newConnection();

        Channel channel = connection.createChannel();
//fanout交换器 qq和email都会收到消息
String fanoutExchangexchangeName = "exchange_fanout_inform";

String fanoutQueueNameEmail = "queue_fanout_email";

String fanoutQueueNameQq = "queue_fanout_qq";

String fanoutRoutKey = "";
//表示声明了一个队列
channel.queueDeclare(fanoutQueueNameEmail,true,false,false,null);
//建立一个绑定关系
channel.queueBind(fanoutQueueNameEmail,fanoutExchangexchangeName,fanoutRoutKey,null);
//email接收消息
channel.basicConsume(fanoutQueueNameEmail,true,new DefaultConsumer(channel){

    @Override

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

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

    }

});
//qq接收消息
channel.queueDeclare(fanoutQueueNameQq,true,false,false,null);
//建立一个绑定关系
channel.queueBind(fanoutQueueNameQq,fanoutExchangexchangeName,fanoutRoutKey,null);

channel.basicConsume(fanoutQueueNameQq,true,new DefaultConsumer(channel){

    @Override

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

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

    }

});

 

}

}

 

2.4 Topic Exchange(主题,规则匹配)

所有发送到Topic Exchange的消息被转发到所有关系RouteKey中指定Topic的Queue上

Exchange将RouteKey和某Topic进行模糊匹配,此时队列需要绑定一个Topic

注意:可以使用通配符进行模糊匹配

符号:“#” 匹配一个或者多个词

符号:“*” 匹配不多不少一个词

列如:

“log.#” 能够匹配到 “log.info.oa”

“log.*” 能够匹配到 “log.err”

 

java rabbitmq学习 rabbitmq详细教程_数据_09

 

 

#生产方代码

public class ProduceTest {

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

        ConnectionFactory connectionFactory = new ConnectionFactory();

        connectionFactory.setHost("127.0.0.1");

        connectionFactory.setPort(5672);

        connectionFactory.setUsername("guest");

        connectionFactory.setPassword("guest");

        connectionFactory.setVirtualHost("/");//rabbitmq默认虚拟机名称为“/”,虚拟机相当于一个独立的mq服

        Connection connection = null;

        Channel channel = null;

        try {

            //创建与RabbitMQ服务的TCP连接 

             connection = connectionFactory.newConnection();

            channel = connection.createChannel();
//topic
String topicExchangeName = "exchange_topic_inform";

String topicRoutKey1 = "info.email";

String topicRoutKey2 = "info.qq";

String topicMessage1 = "topic的email消息消息";

String topicMessage2 = "topic的qq消息";

channel.exchangeDeclare(topicExchangeName,BuiltinExchangeType.TOPIC);

channel.basicPublish(topicExchangeName,topicRoutKey1,null,topicMessage1.getBytes());

channel.basicPublish(topicExchangeName,topicRoutKey2,null,topicMessage2.getBytes());
}catch (Exception e){

            e.printStackTrace();

        }finally {

            if (channel!=null){

                channel.close();

            }

            if(connection!=null){

                connection.close();

            }

        }

    }

}


#消费方代码

public class ConsumerTest {

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

        ConnectionFactory connectionFactory = new ConnectionFactory();

        connectionFactory.setHost("127.0.0.1");

        connectionFactory.setPort(5672);

        connectionFactory.setUsername("guest");

        connectionFactory.setPassword("guest");

        connectionFactory.setVirtualHost("/");//rabbitmq默认虚拟机名称为“/”,虚拟机相当于一个独立的mq服

        Connection connection = connectionFactory.newConnection();

        Channel channel = connection.createChannel();
//topic
String topicExchangeName = "exchange_topic_inform";

String topicQueueNameEmail = "queue_fanout_email";

String topicQueueNameQq = "queue_fanout_qq";

String topicQueueNameAll = "queue_fanout_All";

String topicRoutKey1 = "#.email";  //接收email为后缀的路由键消息
String topicRoutKey2 = "#.qq";  //匹配qq为尾的消息
String topicRoutKey3 = "info.#"; //匹配info开头的消息

//声明队列
channel.queueDeclare(topicQueueNameEmail,true,false,false,null);
//建立一个绑定关系
channel.queueBind(topicQueueNameEmail,topicExchangeName,topicRoutKey1,null);
//email接收消息
channel.basicConsume(topicQueueNameEmail,true,new DefaultConsumer(channel){

    @Override

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

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

    }

});
//qq接收消息
channel.queueDeclare(topicQueueNameQq,true,false,false,null);
//建立一个绑定关系
channel.queueBind(topicQueueNameQq,topicExchangeName,topicRoutKey2,null);
//email接收消息
channel.basicConsume(topicQueueNameQq,true,new DefaultConsumer(channel){

    @Override

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

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

    }

});
//接收所有消息
channel.queueDeclare(topicQueueNameAll,true,false,false,null);
//建立一个绑定关系
channel.queueBind(topicQueueNameAll,topicExchangeName,topicRoutKey3,null);
//email接收消息
channel.basicConsume(topicQueueNameAll,true,new DefaultConsumer(channel){

    @Override

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

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

    }

});

 

}

}

 

 2.5Header交换机Header Exchange

header模式与routing不同的地方在于,header模式取消routingkey,使用header中的 key/value(键值对)匹配队列。

#生产方代码

public class ProduceTest {

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

        ConnectionFactory connectionFactory = new ConnectionFactory();

        connectionFactory.setHost("127.0.0.1");

        connectionFactory.setPort(5672);

        connectionFactory.setUsername("guest");

        connectionFactory.setPassword("guest");

        connectionFactory.setVirtualHost("/");//rabbitmq默认虚拟机名称为“/”,虚拟机相当于一个独立的mq服

        Connection connection = null;

        Channel channel = null;

        try {

            //创建与RabbitMQ服务的TCP连接 

             connection = connectionFactory.newConnection();

            channel = connection.createChannel();
//header
String headerExchangeName = "exchange_header_inform";
//发送email
Map<String,Object> emailMap  = new Hashtable<>();

emailMap.put("info_type","email");

String headMessage1 = "header的email消息";

channel.exchangeDeclare(headerExchangeName,BuiltinExchangeType.HEADERS);

Builder builder = new BasicProperties().builder();

builder.headers(emailMap);

channel.basicPublish(headerExchangeName,"",builder.build(),headMessage1.getBytes());
//发送qq
Map<String,Object> qqMap  = new Hashtable<>();

qqMap.put("info_type","qq");

String headMessage2 = "header的qq消息";

channel.exchangeDeclare(headerExchangeName,BuiltinExchangeType.HEADERS);

Builder builderQQ = new BasicProperties().builder();

builderQQ.headers(qqMap);

channel.basicPublish(headerExchangeName,"",builderQQ.build(),headMessage2.getBytes());
}catch (Exception e){

            e.printStackTrace();

        }finally {

            if (channel!=null){

                channel.close();

            }

            if(connection!=null){

                connection.close();

            }

        }

    }

}


#消费方代码

public class ConsumerTest {

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

        ConnectionFactory connectionFactory = new ConnectionFactory();

        connectionFactory.setHost("127.0.0.1");

        connectionFactory.setPort(5672);

        connectionFactory.setUsername("guest");

        connectionFactory.setPassword("guest");

        connectionFactory.setVirtualHost("/");//rabbitmq默认虚拟机名称为“/”,虚拟机相当于一个独立的mq服

        Connection connection = connectionFactory.newConnection();

        Channel channel = connection.createChannel();
//header
String headerExchangeName = "exchange_header_inform";
//email接收消息
String headerQueueNameEmail = "queue_header_email";

Map<String,Object> emailMap  = new Hashtable<>();

emailMap.put("info_type","email");

channel.queueDeclare(headerQueueNameEmail,true,false,false,null);

channel.queueBind(headerQueueNameEmail,headerExchangeName,"",emailMap);

channel.basicConsume(headerQueueNameEmail,true,new DefaultConsumer(channel){

    @Override

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

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

    }

});
//qq
String headerQueueNameQq = "queue_header_qq";

Map<String,Object> qqMap  = new Hashtable<>();

qqMap.put("info_type","qq");

channel.queueDeclare(headerQueueNameQq,true,false,false,null);

channel.queueBind(headerQueueNameQq,headerExchangeName,"",qqMap);

channel.basicConsume(headerQueueNameQq,true,new DefaultConsumer(channel){

    @Override

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

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

    }

});

 

}

}

三.Spring整合rabbitmq

测试代码Github地址:https://github.com/zhouyanger/java_demo/tree/master/spring-rabbitmq

这里以topic交换机为例,其他类似。

3.1新建spring-rabbitmq项目,导入spring和spring-rabbit包

3.2配置spring-rabbit.xml

 3.2.1生产方配置

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"

       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

       xmlns:context="http://www.springframework.org/schema/context"

       xmlns:aop="http://www.springframework.org/schema/aop"

       xmlns:rabbit="http://www.springframework.org/schema/rabbit"

       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd 

       http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd 

       http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd

        http://www.springframework.org/schema/rabbit

          http://www.springframework.org/schema/rabbit/spring-rabbit.xsd">

    <!-- 1. 配置连接 -->

    <rabbit:connection-factory  id="connectionFactory" host="127.0.0.1" 

                                port="5672" username="guest" password="guest" virtual-host="/"/>

    <!-- 2. 配置队列 

    durable:是否持久化

exclusive: 仅创建者可以使用的私有队列,断开后自动删除

auto_delete: 当所有消费客户端连接断开后,是否自动删除队列-->

    <rabbit:queue name="myQueue" durable="true" auto-declare="false" exclusive="false"/>

    <!-- 3.配置rabbitAdmin -->

    <rabbit:admin connection-factory="connectionFactory"/>

    <!-- 4. 配置topic类型exchange;队列绑定到交换机durable:是否持久化 auto_delete: 当所有消费客户端连接断开后,是否自动删除队列 -->

    <rabbit:topic-exchange name="myExchange" auto-delete="false" durable="true">

        <rabbit:bindings>

            <rabbit:binding  queue="myQueue" pattern="msg.#"/>

        </rabbit:bindings>

    </rabbit:topic-exchange>

    <!-- 5. 配置消息对象json转换类 -->

    <bean id="jsonMessageConverter" class="org.springframework.amqp.support.converter.Jackson2JsonMessageConverter" />

    <!-- 6. 配置RabbitTemplate -->

    <rabbit:template id="rabbitTemplate" 

                     connection-factory="connectionFactory" 

                     exchange="myExchange" 

                     message-converter="jsonMessageConverter"/>

   </beans>

 3.2.2 发送消息

@RunWith(value = SpringJUnit4ClassRunner.class)

@ContextConfiguration(locations = {"classpath:spring-rabbit.xml"})
public class Test {

    @Autowired

    private RabbitTemplate rabbitTemplate;

    @org.junit.Test

    public void test(){

        Map<String,String> map = new HashMap<>();

        map.put("name","zhouyang");

        rabbitTemplate.convertAndSend("msg.qq",map);

    }

}

3.3.4 消费方新建一个监听器

@Component
public class ConsumerListenner implements MessageListener {

    @Override

    public void onMessage(Message message) {

        System.out.println(message.toString());

    }

}

3.3.5配置消费方的监听器xml

<!---消费端配置监听,队列信息-->
<rabbit:listener-container connection-factory="connectionFactory" acknowledge="auto">

    <rabbit:listener ref="consumerListenner" queues="myQueue"/>

</rabbit:listener-container>

    

    <context:component-scan base-package="com.zy"/>

3.4测试


四.Springboot整合rabbitmq

 

测试代码github地址:https://github.com/zhouyanger/java_demo/tree/master/springboot-rabbitmq

4.1新建rabbitmq-producer

#导包

<dependency> <groupId>org.springframework.boot</groupId>

    <artifactId>spring-boot-starter-amqp</artifactId>

</dependency>

#配置application.yml

server:

  port: 8481
spring:

  application:

    name: rabbit-producer

  rabbitmq:

    host: localhost

    port: 5672

    virtual-host: /

    username: guest

    password: guest
#新建RabbitmqProducerConfig,配置生产方信息
@Configuration

public class RabbitmqProducerConfig
{

    //交换机配置

    @Bean

    public Exchange testExchange(){

        return ExchangeBuilder.topicExchange("topic_exchange").durable(true).build();

    }

    //声明一个队列

    @Bean

    public Queue testQueue(){

        return new Queue("qqQueue",true,false,false);

    }

    //绑定队列和交换机

    @Bean

    public Binding tesBinding(){

        return BindingBuilder.bind(testQueue()).to(testExchange()).with("info.#").noargs();

    }

}

#测试

@SpringBootTest
class RabbitmqProducerApplicationTests {

@Autowired
private RabbitTemplate rabbitTemplate;

    @Test

    void contextLoads() {

    }

    @Test

    void testProducer(){

        Map<String,String> map = new HashMap<>();

        map.put("name","zhouyang");

    rabbitTemplate.convertAndSend("topic_exchange","info.qq",map);

}

}


4.2新建rabbitmq-consumer

#导包

<dependency> <groupId>org.springframework.boot</groupId>

    <artifactId>spring-boot-starter-amqp</artifactId>

</dependency>

#配置application.yml

server:

  port: 8482
spring:

  application:

    name: rabbit-consumer

  rabbitmq:

    host: localhost

    port: 5672

    virtual-host: /

    username: guest

    password: guest
#新建RabbitmqConsumerConfig配置类(消费者单纯的使用,其实可以不用添加这个配置,直接建后面的监听就好,使用注解来让监听器监听对应的队列即可。配置上了的话,其实消费者也是生成者的身份,也能推送该消息。)
@Configuration
public class RabbitmqConsumerConfig {

    //交换机配置

    @Bean

    public Exchange testExchange(){

        return ExchangeBuilder.topicExchange("topic_exchange").durable(true).build();

    }

    //声明一个队列

    @Bean

    public Queue testQueue(){

        return new Queue("qqQueue",true,false,false);

    }

    //绑定队列和交换机

    @Bean

    public Binding tesBinding(){

        return BindingBuilder.bind(testQueue()).to(testExchange()).with("info.#").noargs();

    }

}
#新建监听器
@Component

@RabbitListener(queues = "qqQueue")
public class MyRabbitListenner {

    @RabbitHandler

    public void getMessage(Map map){

        System.out.println("qq接收到的消息"+map);

    }

}
测试,启动了producer项目,然后启动consumer项目,得到结果

 

java rabbitmq学习 rabbitmq详细教程_TCP_10

 

 

其他类型的交换机配置差不多,这里就不举例了