下载带有管理界面的RabbitMQ Docker镜像
docker pull rabbitmq:3.7.7-management
然后创建并运行RabbitMQ容器
docker run -d --name rabbitmq3.7.7 -p 5672:5672 -p 15672:15672 -v `pwd`/data:/var/lib/rabbitmq --hostname myRabbit -e RABBITMQ_DEFAULT_VHOST=my_vhost -e RABBITMQ_DEFAULT_USER=admin -e RABBITMQ_DEFAULT_PASS=admin rabbitmq:3.7.7-management docker run -d --hostname rabbitmqhost --name rabbitmq3.6 --restart always -p 5672:5672 -p 15672:15672 -e RABBITMQ_DEFAULT_USER=admin -e RABBITMQ_DEFAULT_PASS=admin rabbitmq:3.6.15-management
-d:后台运行
--hostname:设置容器的主机名
--name:容器命名
--restart always:开机启动
-p:端口号映射,前面是宿主机端口,后面是容器端口
-v:挂载宿主机目录到容器目录
-e:设置容器环境变量
游览器访问:http://服务器ip地址:15672
输入启动容器是设置的用户名密码登录就进去管理页面啦
交换机的主要功能是接收消息并转发到绑定的队列,交换机自身不存储消息,当启动ack模式后,交换机找不到指定的队列会返回错误。交换机类型有Direct、topic、 Headers、Fanout四种类型
Direct Exchange 是 RabbitMQ 默认的交换机模式,也是最简单的模式,根据key全文匹配去寻找队列。发送消息是设置一个routing_key,当routing_key匹配时才将消息传送到绑定的队列中。
Topic Exchange跟Direct Exchange类似,在匹配上增加了模式概念,从以点分开的routing_key形式中,可用使用2中统配符:*表示一个单词,#表示0个或者多个单词
Headers Exchange是一个自定义匹配规则的类型,在交换器与队列绑定时,会制定一组键值对规则,发送消息时也会制定一组规则,当这些键值对有一对或者多对匹配时,消息会传送到对应的队列中。
Fanout Exchange用的是消息广播模式,设置路由建无效,它会把消息传送给交换机下的所有队列。
创建一个主工程:spring-boot-rabbitmq,添加如下内容:
<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <!--<version>2.1.5.RELEASE</version>--> <version>1.5.20.RELEASE</version> </parent> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <java.version>1.8</java.version> <spring-boot.version>1.5.20.RELEASE</spring-boot.version> </properties> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-dependencies</artifactId> <version>${spring-boot.version}</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement>
在spring-boot-rabbitmq主工程中创建一个RabbitMQ配置的Maven module:rabbitmq-config
添加如下依赖:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-amqp</artifactId> </dependency>
创建一个配置类:RabbitConfig.java,添加如下内容
@Configuration public class RabbitConfig { //创建一个hello-queue消息队列 @Bean public Queue helloQueue() { return new Queue("hello-queue"); } }
在spring-boot-rabbitmq主工程中创建一个消息发送方的SpringBoot module:rabbitmq-sender
在pom文件中添加如下依赖:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>com.alyshen</groupId> <artifactId>rabbitmq-config</artifactId> <version>${project.version}</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-amqp</artifactId> </dependency>
在resource目录下创建配置文件:application.properties,添加如下内容:
############### 服务配置 ############# server.port=9000 spring.application.name=rabbitmq-sender ############### RabbitMQ配置 ############## spring.rabbitmq.host=192.168.86.101 spring.rabbitmq.port=5672 spring.rabbitmq.username=admin spring.rabbitmq.password=admin
创建工程启动类:RabbitmqSenderApplication.java,添加如下内容:
@SpringBootApplication public class RabbitmqSenderApplication { public static void main(String[] args) { SpringApplication.run(RabbitmqSenderApplication.class,args); } }
创建一个消息生产者:HelloQueueSender.java
@Component public class HelloQueueSender { @Autowired private AmqpTemplate amqpTemplate; public void send(String msg) { String context = msg + ",sender date:" + new Date(); System.out.println("Sender to hello-queue: " + context); this.amqpTemplate.convertAndSend("hello-queue", context);//使用hello-queue队列 } }
创建一个HelloSenderController供浏览器发送消息,添加如下内容:
@RestController public class HelloSenderController { @Autowired private HelloQueueSender helloQueueSender; @RequestMapping(value = "/senderMessage") public String senderMessage(@PathParam(value = "msg") String msg){ helloQueueSender.send(msg); return "sender ok..."; } }
运行项目rabbitmq-sender,访问:
http://localhost:9000/senderMessage?msg=消息内容
这时消息内容保存到rabbitmq队列中待消息消费方获取
创建一个消息接收方的SpringBoot工程:rabbitmq-receiver
在pom文件中添加如下依赖:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>com.alyshen</groupId> <artifactId>rabbitmq-config</artifactId> <version>${project.version}</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-amqp</artifactId> </dependency>
在resource目录下创建配置文件:application.properties,添加如下内容:
############### 服务配置 ############# server.port=9100 spring.application.name=rabbitmq-receiver ############### RabbitMQ配置 ############## spring.rabbitmq.host=192.168.86.101 spring.rabbitmq.port=5672 spring.rabbitmq.username=admin spring.rabbitmq.password=admin
创建工程启动类:RabbitmqReceiverApplication.java
添加如下内容:
@SpringBootApplication public class RabbitmqReceiverApplication { public static void main(String[] args) { SpringApplication.run(RabbitmqReceiverApplication.class,args); } }
在rabbitmq-receiver的pom文件中加入rabbitmq-config工程依赖
创建一个消息处理者:HelloQueueReceiver.java
@Component @RabbitListener(queues = "hello-queue") public class HelloQueueReceiver { @RabbitHandler public void process(String hello){ System.out.println("Receiver:" + hello); } }
启动工程rabbitmq-receiver,输出内容:
Receiver:消息内容,……
即获取到消息内容
将rabbitmq-sender中的HelloSenderController内容修改成如下所示:
@RestController public class HelloSenderController { @Autowired private HelloQueueSender helloQueueSender; @RequestMapping(value = "/senderMessage") public String senderMessage(@PathParam(value = "msg") String msg) { for (int i = 1; i <= 20; i++) { helloQueueSender.send(i + "," + msg); } return "sender ok..."; } }
把rabbitmq-receiver中的HelloQueueReceiver.java复制一份,分别改成如下:
HelloQueueReceiver.java
@Component @RabbitListener(queues = "hello-queue") public class HelloQueueReceiver { @RabbitHandler public void process(String msg) { System.out.println("Receiver 1:" + msg); } }
HelloQueueReceiver2.java
@Component @RabbitListener(queues = "hello-queue") public class HelloQueueReceiver2 { @RabbitHandler public void process(String msg){ System.out.println("Receiver 2:" + msg); } }
将rabbitmq-sender和rabbitmq-receiver运行起来
访问http://localhost:9000/senderMessage?msg=消息内容
rabbitmq-sender控制台输出:
Sender to hello-queue: 1,消息内容,……
Sender to hello-queue: 2,消息内容,……
Sender to hello-queue: 3,消息内容,……
Sender to hello-queue: 4,消息内容,……
Sender to hello-queue: 5,消息内容,……
Sender to hello-queue: 6,消息内容,……
Sender to hello-queue: 7,消息内容,……
Sender to hello-queue: 8,消息内容,……
Sender to hello-queue: 9,消息内容,……
Sender to hello-queue: 10,消息内容,……
Sender to hello-queue: 11,消息内容,……
Sender to hello-queue: 12,消息内容,……
Sender to hello-queue: 13,消息内容,……
Sender to hello-queue: 14,消息内容,……
Sender to hello-queue: 15,消息内容,……
Sender to hello-queue: 16,消息内容,……
Sender to hello-queue: 17,消息内容,……
Sender to hello-queue: 18,消息内容,……
Sender to hello-queue: 19,消息内容,……
Sender to hello-queue: 20,消息内容,……
rabbitmq-receiver控制台输出:
Receiver 1:1,消息内容,……
Receiver 2:2,消息内容,……
Receiver 1:3,消息内容,……
Receiver 2:4,消息内容,……
Receiver 1:5,消息内容,……
Receiver 2:6,消息内容,……
Receiver 1:7,消息内容,……
Receiver 2:8,消息内容,……
Receiver 1:9,消息内容,……
Receiver 2:10,消息内容,……
Receiver 1:11,消息内容,……
Receiver 2:12,消息内容,……
Receiver 1:13,消息内容,……
Receiver 2:14,消息内容,……
Receiver 1:15,消息内容,……
Receiver 2:16,消息内容,……
Receiver 1:17,消息内容,……
Receiver 2:18,消息内容,……
Receiver 1:19,消息内容,……
Receiver 2:20,消息内容,……
可以看出消息消费方是轮流有序的获取消息的
将rabbitmq-sender中的HelloQueueSender复制一份创建HelloQueueSender2,就类名不一样,其他都一样
改造一下rabbitmq-sender工程中的HelloSenderController,改成入下:
@RestController public class HelloSenderController { @Autowired private HelloQueueSender helloQueueSender; @Autowired private HelloQueueSender2 helloQueueSender2; @RequestMapping(value = "/senderMessage") public String senderMessage(@PathParam(value = "msg") String msg) { for (int i = 1; i <= 20; i++) { helloQueueSender.send("sender1 " + i + "." + msg); helloQueueSender2.send("sender2 " + i + "." + msg); } return "sender ok..."; } }
运行rabbitmq-sender
访问http://localhost:9000/senderMessage?msg=消息内容
rabbitmq-sender控制台输出
Sender to hello-queue: sender1 1.消息内容,……
Sender to hello-queue: sender2 1.消息内容,……
Sender to hello-queue: sender1 2.消息内容,……
Sender to hello-queue: sender2 2.消息内容,……
Sender to hello-queue: sender1 3.消息内容,……
Sender to hello-queue: sender2 3.消息内容,……
Sender to hello-queue: sender1 4.消息内容,……
Sender to hello-queue: sender2 4.消息内容,……
Sender to hello-queue: sender1 5.消息内容,……
Sender to hello-queue: sender2 5.消息内容,……
Sender to hello-queue: sender1 6.消息内容,……
Sender to hello-queue: sender2 6.消息内容,……
Sender to hello-queue: sender1 7.消息内容,……
Sender to hello-queue: sender2 7.消息内容,……
Sender to hello-queue: sender1 8.消息内容,……
Sender to hello-queue: sender2 8.消息内容,……
Sender to hello-queue: sender1 9.消息内容,……
Sender to hello-queue: sender2 9.消息内容,……
Sender to hello-queue: sender1 10.消息内容,……
Sender to hello-queue: sender2 10.消息内容,……
Sender to hello-queue: sender1 11.消息内容,……
Sender to hello-queue: sender2 11.消息内容,……
Sender to hello-queue: sender1 12.消息内容,……
Sender to hello-queue: sender2 12.消息内容,……
Sender to hello-queue: sender1 13.消息内容,……
……
rabbitmq-receiver的控制台输出:
Receiver 1:sender1 1.消息内容,……
Receiver 2:sender2 1.消息内容,……
Receiver 1:sender1 2.消息内容,……
Receiver 2:sender2 2.消息内容,……
Receiver 1:sender1 3.消息内容,……
Receiver 2:sender2 3.消息内容,……
Receiver 1:sender1 4.消息内容,……
Receiver 2:sender2 4.消息内容,……
Receiver 1:sender1 5.消息内容,……
Receiver 2:sender2 5.消息内容,……
Receiver 1:sender1 6.消息内容,……
Receiver 2:sender2 6.消息内容,……
Receiver 1:sender1 7.消息内容,……
Receiver 2:sender2 7.消息内容,……
Receiver 1:sender1 8.消息内容,……
Receiver 2:sender2 8.消息内容,……
Receiver 1:sender1 9.消息内容,……
Receiver 2:sender2 9.消息内容,……
Receiver 2:sender2 10.消息内容,……
Receiver 1:sender1 10.消息内容,……
Receiver 1:sender1 11.消息内容,……
Receiver 2:sender2 11.消息内容,……
Receiver 1:sender1 12.消息内容,……
Receiver 2:sender2 12.消息内容,……
Receiver 2:sender1 13.消息内容,……
Receiver 1:sender2 13.消息内容,……
可以看出在多对多情况下消息依然是有序取出的
在spring-boot-rabbitmq主工程中创建一个model module:rabbitmq-model
添加一个model:User
内容如下:
public class User implements Serializable { public static final Long serialVersionUID = 1L; private String username; private String passwd; private int age; @Override public String toString() { return "User{" + "username='" + username + '\'' + ", passwd='" + passwd + '\'' + ", age=" + age + '}'; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPasswd() { return passwd; } public void setPasswd(String passwd) { this.passwd = passwd; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } }
分别在rabbitmq-sender和rabbitmq-receiver工程中加入rabbitmq-model依赖
<dependency> <groupId>com.alyshen</groupId> <artifactId>rabbitmq-model</artifactId> <version>${project.version}</version> </dependency>
在rabbitmq-config工程中的配置类RabbitmqConfig.java加入方法:
//创建一个user-queue消息队列 @Bean public Queue userQueue() { return new Queue("user-queue"); }
在rabbitmq-sender工程中参加一个生产方:UserSender.java,内容如下:
@Component public class UserSender { @Autowired private AmqpTemplate amqpTemplate; public void senderUser(User user) { System.out.println("Sender to user-queue: " + user); amqpTemplate.convertAndSend("user-queue",user); } }
在添加一个Controller:UserSenderController.java,内容如下:
@RestController public class UserSenderController { @Autowired UserSender userSender; @RequestMapping(value = "/sendUser") public String senduser() { User user = new User(); user.setUsername("zhangshan"); user.setPasswd("zzzpwd"); user.setAge(20); userSender.senderUser(user); return "sender user ok ..."; } }
运行rabbitmq-sender工程,浏览器访问:http://localhost:9000/sendUser,控制台输出:
Sender to user-queue: User{username='zhangshan', passwd='zzzpwd', age=20}
一个username为zhangshan的User就加入了user-queue队列中
现在rabbitmq-receiver工程中创建一个User消息接收方:UserReceiver.java,内容如下:
@Component public class UserReceiver { // @RabbitHandler @RabbitListener(queues = "user-queue") public void process(User user) { System.out.println("Receiver user:" + user); } }
运行rabbitmq-receiver工程,控制台输出:
Receiver user:User{username='zhangshan', passwd='zzzpwd', age=20}
User信息接收成功
在rabbitmq-config工程中创建配置类TopicRabbitConfig.java,内容如下:
@Configuration public class TopicRabbitConfig { final static String message = "topic.message"; final static String messages = "topic.messages"; @Bean public Queue queueMessage() { return new Queue(TopicRabbitConfig.message); } @Bean public Queue queueMessages() { return new Queue(TopicRabbitConfig.messages); } /** * @Title exchange * @Description 创建个Topic交换机 */ @Bean TopicExchange exchange() { return new TopicExchange("topicExchange"); } /** * @Title bindingExchangeMessage * @Description 交换机和路由建绑定 */ @Bean Binding bindingExchangeMessage(Queue queueMessage, TopicExchange exchange) { return BindingBuilder.bind(queueMessage).to(exchange).with("topic.message"); } @Bean Binding bindingExchangeMessages(Queue queueMessages, TopicExchange exchange) { return BindingBuilder.bind(queueMessages).to(exchange).with("topic.#"); } }
在rabbitmq-sender工程中添加topic消息发送方:TopicSender.java,添加如下内容:
@Component public class TopicSender { @Autowired private AmqpTemplate rabbitTemplate; public void sender() { String context = "消息1..."; System.out.println("Sender : " + context); this.rabbitTemplate.convertAndSend("topicExchange", "topic.xxx", context); } public void sender2() { String context = "消息2..."; System.out.println("Sender : " + context); this.rabbitTemplate.convertAndSend("topicExchange", "topic.message", context); } public void sender3() { String context = "消息3..."; System.out.println("Sender : " + context); this.rabbitTemplate.convertAndSend("topicExchange", "topic.messages", context); } }
再创建一个TopicSenderController,添加如下内容:
@RestController public class TopicSenderController { @Autowired private TopicSender topicSender; @RequestMapping(value = "/topic") public String topic() { topicSender.sender(); return "sender ok..."; } @RequestMapping(value = "/topic2") public String topic2() { topicSender.sender2(); return "sender ok..."; } @RequestMapping(value = "/topic3") public String topic3() { topicSender.sender3(); return "sender ok..."; } }
在rabbitmq-receiver工程中创建topic消息接收端:TopicReceiver1.java,添加如下内容:
@Component public class TopicReceiver1 { // @RabbitHandler @RabbitListener(queues = "topic.message") public void process(String message) { System.out.println("Topic Receiver 1:" + message); } }
在创建一个topic消息接收端:TopicReceiver2.java,添加如下内容:
@Component public class TopicReceiver2 { // @RabbitHandler @RabbitListener(queues = "topic.messages") public void process(String message) { System.out.println("Topic Receiver 2:" + message); } }
运行rabbitmq-sender和rabbitmq-receiver
浏览器访问:http://localhost:9000/topic
发现只有Receiver 2接收到消息1,说明topic.xxx匹配的是topic.#这个规则
浏览器访问:http://localhost:9000/topic2
发现Receiver 1和Receiver 2都接收到了消息2,说明topic.message匹配的是topic.message和topic.#这两个规则
浏览器访问:http://localhost:9000/topic3
发现只有Receiver 2都接收到了消息3,说明topic.messages匹配的是topic.#这个规则
在rabbitmq-config工程中创建配置类FanoutRabbitConfig.java,添加如下内容:
@Configuration public class FanoutRabbitConfig { //创建队列a @Bean public Queue AMessage() { return new Queue("fanout.A"); } @Bean public Queue BMessage() { return new Queue("fanout.B"); } @Bean public Queue CMessage() { return new Queue("fanout.C"); } // 创建Fanout 交换机 @Bean FanoutExchange fanoutExchange() { return new FanoutExchange("fanoutExchange"); } //队列绑定交换机 @Bean Binding bindingExchangeA(Queue AMessage, FanoutExchange fanoutExchange) { return BindingBuilder.bind(AMessage).to(fanoutExchange); } @Bean Binding bindingExchangeB(Queue BMessage, FanoutExchange fanoutExchange) { return BindingBuilder.bind(BMessage).to(fanoutExchange); } @Bean Binding bindingExchangeC(Queue CMessage, FanoutExchange fanoutExchange) { return BindingBuilder.bind(CMessage).to(fanoutExchange); } }
在rabbitmq-sender工程中添加fanout消息发送方:FanoutSender.java,添加如下内容:
@Component public class FanoutSender { @Autowired private AmqpTemplate rabbitTemplate; public void sender() { String context = "fanout 消息内容..."; System.out.println("Sender : " + context); this.rabbitTemplate.convertAndSend("fanoutExchange", "", context); } }
再创建一个FanoutSenderController,添加如下内容:
@RestController public class FanoutSenderController { @Autowired private FanoutSender fanoutSender; @RequestMapping(value = "/fanout") public String topic() { fanoutSender.sender(); return "sender ok..."; } }
在rabbitmq-receiver工程中创建fanout消息接收端:FanoutReceiver.java,添加如下内容:
@Component public class FanoutReceiver { // @RabbitHandler @RabbitListener(queues = "fanout.A") public void process(String message) { System.out.println("fanout Receiver A:" + message); } @RabbitListener(queues = "fanout.B") public void process2(String message) { System.out.println("fanout Receiver B:" + message); } @RabbitListener(queues = "fanout.C") public void process3(String message) { System.out.println("fanout Receiver C:" + message); } }
运行rabbitmq-sender和rabbitmq-receiver
浏览器访问:http://localhost:9000/fanout
在rabbitmq-receiver工程的控制台下输出:
fanout Receiver B:fanout 消息内容...
fanout Receiver C:fanout 消息内容...
fanout Receiver A:fanout 消息内容...
说明绑定到fanout交换机上的队列都接收到了消息