#1、概述
1.在大多应用中,我们系统之间需要进行异步通信,即异步消息。
2.异步消息中两个重要概念:
3.异步消息主要有两种形式的目的地
4.点对点式:
5.发布订阅式:
6.JMS(Java Message Service)java消息服务:
7.AMQP(Advanced Message Queuing Protocol)
8.Spring支持
9.Spring Boot自动配置
##2.1 RabbitMQ简介
RabbitMQ是一个由erlang开发的AMQP(Advanved Message Queue)的开源实现。
核心概念
Producer&Consumer:producer指的是消息生产者,consumer消息的消费者
Broker:它提供一种传输服务,它的角色就是维护一条从生产者到消费者的路线,保证数据能按照指定的方式进行传输;
Queue
Exchange
Binding
virtual host(vhosts )
RabbitMQ运行机制:
##2.2 安装RabbitMQ(docker)
在安装了docker的服务器上,执行命令:docker pull rabbitmq:3-management (management:表示带有管理界面的)
安装完成,执行命令运行:docker run -d -p 5672:5672 -p 15672:15672 --name myrabbitmq 镜像ID
启动成功之后,就可以在浏览器访问:http://192.168.0.105:15672/
使用用户名和密码登录:guest/guest
就会进入到管理界面,可以使用可视化的界面进行相关的操作,具体自行学习。
#3、整合RabbitMQ
使用SpringBoot的向导创建工程springboot-02-amqp,选中web模块和RabbitMQ模块;SpringBoot的版本:2.2.6
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0modelVersion>
<parent>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-parentartifactId>
<version>2.2.6.RELEASEversion>
<relativePath/>
parent>
<groupId>com.springboot.amqpgroupId>
<artifactId>springboot-02-amqpartifactId>
<version>0.0.1-SNAPSHOTversion>
<name>springboot-02-amqpname>
<description>Demo project for Spring Bootdescription>
<properties>
<java.version>1.8java.version>
properties>
<dependencies>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-amqpartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-testartifactId>
<scope>testscope>
<exclusions>
<exclusion>
<groupId>org.junit.vintagegroupId>
<artifactId>junit-vintage-engineartifactId>
exclusion>
exclusions>
dependency>
<dependency>
<groupId>org.springframework.amqpgroupId>
<artifactId>spring-rabbit-testartifactId>
<scope>testscope>
dependency>
<dependency>
<groupId>junitgroupId>
<artifactId>junitartifactId>
<scope>testscope>
dependency>
dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-maven-pluginartifactId>
plugin>
plugins>
build>
project>
##3.2 application.yml
对RabbitMQ做一个简单的配置:
spring:
rabbitmq:
host: 192.168.0.105
username: guest
password: guest
导入AMQP的启动器之后,默认给我们注入的是SimpleMessageConverter,它的序列化方式是使用Jdk序列化成二进制数据,不易读取,所以我们要定义一个序列化为json的MessageConverter:
package com.springboot.amqp.config;
import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter;
import org.springframework.amqp.support.converter.MessageConverter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class MyAMQPConfig {
//定义一个序列化为JSON的MessageConverter,添加导容器中
@Bean
public MessageConverter messageConverter(){
return new Jackson2JsonMessageConverter();
}
}
package com.springboot.amqp.bean;
import java.util.Date;
public class Person {
private int id;
private String name;
private boolean gender;
private Date birthday;
//无参构造一定要加
public Person() {
}
public Person(int id, String name, boolean gender, Date birthday) {
this.id = id;
this.name = name;
this.gender = gender;
this.birthday = birthday;
}
@Override
public String toString() {
return "Person{" +
"id=" + id +
", name='" + name + '\'' +
", gender=" + gender +
", birthday=" + birthday +
'}';
}
//get/set方法
}
注意:添加了有参构造,无参构造也一定要加上,否则后面会出错。这也是一个习惯,无参构造不能省,很多的框架都是使用反射技术的,都会用到无参构造,如果没有就会抛异常
package com.springboot.amqp.service;
import com.springboot.amqp.bean.Person;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Service;
@Service
public class PersonService {
@RabbitListener(queues = "zdw.news")
public void receive(Person person){
try {
Thread.sleep(6000*2);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("从zdw.news队列接收的消息:"+person);
}
@RabbitListener(queues = "zxh.news")
public void receive2(Message message){
try {
Thread.sleep(6000*2);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(message.getBody().toString());
System.out.println(message.getMessageProperties());
}
}
使用注解@RabbitListener 来监听队列,只要队列中有消息,并且该方法本身是空闲的时候,就会从队列中获取消息进行消费。
##3.6 启动类添加注解@EnableRabbot
@EnableRabbit :开启基于注解的RabbitMQ模式
package com.springboot.amqp;
import org.springframework.amqp.rabbit.annotation.EnableRabbit;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
* 自动配置
* 1、RabbitAutoConfiguration
* 2、有自动配置了连接工厂ConnectionFactory;
* 3、RabbitProperties 封装了 RabbitMQ的配置
* 4、 RabbitTemplate :给RabbitMQ发送和接受消息;
* 5、 AmqpAdmin : RabbitMQ系统管理功能组件;
* AmqpAdmin:创建和删除 Queue,Exchange,Binding
* 6、@EnableRabbit + @RabbitListener 监听消息队列的内容
*
*/
@EnableRabbit //开启基于注解的RabbitMQ模式
@SpringBootApplication
public class Springboot02AmqpApplication {
public static void main(String[] args) {
SpringApplication.run(Springboot02AmqpApplication.class, args);
}
}
package com.springboot.amqp;
import com.springboot.amqp.bean.Person;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.amqp.core.AmqpAdmin;
import org.springframework.amqp.core.Binding;
import org.springframework.amqp.core.DirectExchange;
import org.springframework.amqp.core.Queue;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
@RunWith(SpringRunner.class)
@SpringBootTest
public class Springboot02AmqpApplicationTests {
@Autowired
RabbitTemplate rabbitTemplate;
//测试发送字符串和map以及list
@Test
public void contextLoads() {
//rabbitTemplate.convertAndSend("zdw.direct","zdw","我的第一个消息");
Map<String,Object> map = new HashMap<>();
map.put("msg","这是第一个JSON消息");
map.put("data", Arrays.asList("RabbitMq",10000,true));
rabbitTemplate.convertAndSend("zdw.fanout","aaa",map);
}
//测试发送对象
@Test
public void testObject() {
Person person = new Person(1001,"张无忌",true,new Date());
rabbitTemplate.convertAndSend("zdw.topic","*.news",person);
}
//测试接收消息
@Test
public void testReceive() {
Object o = rabbitTemplate.receiveAndConvert("zxh.news");
System.out.println(o.getClass());
System.out.println(o);
}
@Autowired
AmqpAdmin amqpAdmin;
//测试创建交换机等操作
@Test
public void testAdminAmqp(){
//创建交换机
amqpAdmin.declareExchange(new DirectExchange("amqpadmin.exchange"));
System.out.println("创建交换机完成");
//创建队列
amqpAdmin.declareQueue(new Queue("amqpadmin.queue",true));
System.out.println("创建队列完成");
//创建绑定规则,把队列绑定到交换机
amqpAdmin.declareBinding(new Binding("amqpadmin.queue", Binding.DestinationType.QUEUE,"amqpadmin.exchange","amqp.haha",null));
System.out.println("交换机和队列绑定成功...");
}
}