大多数应用中,可以通过消息服务中间件来提升系统异步通信和扩展解耦能力
消息服务中有两个重要概念:消息代理(message broker)和目的地(destination),当消息发送者发送消息以后,将由消息代理接管,消息代理保证消息传递到指定目的地
消息队列主要由两种形式的目的地:
队列(queue):点对点通信(point to point)
主题(topic):发布(publish)/订阅(subscribe)消息通信
RabbitMQ是AMQP的实现
spring-jms提供了对JMS的支持
SpringBoot只需要导入相应的场景启动器即可
rabbitmq是一个有erlang开发的AMQP的开源实现。
核心概念:
Direct Exchange
消息中的路由键(routing key)如果和Binding中的binding key一致,交换器就将消息发送到对应的队列中,路由键和队列名完全匹配,是完全匹配、单播的模式。
Fanout Exchange
每个发到fanout类型交换器的消息都会分到所有绑定的队列上去,fanout交换器不处理路由键,只是简单的将队列绑到交换器上,每个发送到交换器的消息都会被转发到与该交换器绑定的所有队列上,类似子网广播,每台子网内的主机都获得了一份复制的消息,fanout类型交换器转发消息是最快的。
Topic Exchange
topic交换器通过模式匹配分配消息的路由键属性,将路由键和某个模式进行匹配,此时队列需要绑定到一个模式上,它将路由键和绑定键的字符串切分成单词,这些单词之间用点隔开,它同样也会识别两个通配符:#
和*
,#
匹配0个或多个单词,*
匹配一个单词。
准备rabbitmq环境:
docker pull rabbitmq:3.8-management #如果不用management版本的话可能会出现一些奇怪的错误,搜不到的那种哦!
docker run -d -p 5672:5672 -p 15672:15672 --name myrabbitmq01 镜像id
修改消息转换器:
@Configuration
public class RmqConfig {
@Bean
public MessageConverter myMessageConverter(){
return new Jackson2JsonMessageConverter(); //使用Jackson的消息转换器
}
}
测试消息发送和接收:
@SpringBootTest
class Springboot02RabbitmqApplicationTests {
@Autowired
private RabbitTemplate rabbitTemplate;
@Test
void send() {
//rabbitTemplate.send(exchange,routingkey,messsage);
Map<String,Object> map = new HashMap<>();
map.put("msg","A message");
map.put("list", Arrays.asList(1,2,3,4,5));
rabbitTemplate.convertAndSend("exchange.direct","yxy",map);
System.out.println("发送完毕!");
}
@Test
void receive(){
Object o = rabbitTemplate.receiveAndConvert("yxy");
System.out.println("消息类型:"+o.getClass());
System.out.println("消息内容:"+o);
}
}
可以发现序列化和反序列化都是成功的。(自定义的对象也可以,但是一定保证有无参构造方法和set方法,不然会报错);
@RabbitListener:标注在方法上,可以监听特定的消息队列,一旦队列中有消息,立刻接收(需要先开启注解模式,@EnableRabbit,标注在springboot启动类上)
@Service
public class UserService {
/**
* @RabbitListener:监听消息队列,有消息就接收,速度非常快,刚发完消息,立马就收到了
* @param user 自动转化类型
*/
@RabbitListener(queues = {
"yxy"})
public void receive(User user){
System.out.println("收到消息:"+user);
}
/**
* @param message 也可以用message来接收消息
*/
@RabbitListener(queues = {
"yxy.news"})
public void receiveMessage(Message message){
System.out.println("消息体:"+message.getBody());
System.out.println("消息头:"+message.getMessageProperties());
}
/**
* 操作交换机,队列,绑定规则等
*/
@Test
void create(){
amqpAdmin.declareExchange(new DirectExchange("amqpadmin.direct"));
amqpAdmin.declareQueue(new Queue("amqpadmin.queue"));
amqpAdmin.declareBinding(new Binding(
"amqpadmin.queue", Binding.DestinationType.QUEUE
,"amqpadmin.direct"
,"amqpadmin.direct"
, null));
}
}