1. 在大多应用中,我们系统之间需要进行异步通信,即异步消息。
2. 异步消息中两个重要概念: 消息代理(message broker)和目的地(destination) 当消息发送者发送消息以后,将由消息代理接管,消息代理保证消息传递到指定目 的地。 3. 异步消息主要有两种形式的目的地 1. 队列(queue):点对点消息通信(point-to-point) 2. 主题(topic):发布(publish)/订阅(subscribe)消息通信
4. 点对点式: – 消息发送者发送消息,消息代理将其放入一个队列中,消息接收者从队列中获取消息内容, 消息读取后被移出队列 – 消息只有唯一的发送者和接受者,但并不是说只能有一个接收者
5. 发布订阅式: – 发送者(发布者)发送消息到主题,多个接收者(订阅者)监听(订阅)这个主题,那么 就会在消息到达时同时收到消息
6. JMS(Java Message Service)java消息服务: – 基于JVM消息代理的规范。ActiveMQ、HornetMQ是JMS实现
7. AMQP(Advanced Message Queuing Protocol) – 高级消息队列协议,也是一个消息代理的规范,兼容JMS – RabbitMQ是AMQP的实现
8. Spring支持 – spring-jms提供了对JMS的支持 – spring-rabbit提供了对AMQP的支持 – 需要ConnectionFactory的实现来连接消息代理 – 提供JmsTemplate、RabbitTemplate来发送消息 – @JmsListener(JMS)、@RabbitListener(AMQP)注解在方法上监听消息代理发 布的消息 – @EnableJms、@EnableRabbit开启支持
9. Spring Boot自动配置 – JmsAutoConfiguration – RabbitAutoConfiguration
RabbitMQ简介: RabbitMQ是一个由erlang开发的AMQP(Advanved Message Queue)的开源实现。
核心概念:
Producer&Consumer
producer指的是消息生产者,
consumer消息的消费者。
Broker – 它提供一种传输服务,它的角色就是维护一条从生产者到消费者的路线,保 证数据能按照指定的方式进行传输,
Queue – 消息队列,提供了FIFO的处理机制,具有缓存消息的能力。rabbitmq中, 队列消息可以设置为持久化,临时或者自动删除。 – 设置为持久化的队列,queue中的消息会在server本地硬盘存储一份,防止 系统crash,数据丢失 – 设置为临时队列,queue中的数据在系统重启之后就会丢失 – 设置为自动删除的队列,当不存在用户连接到server,队列中的数据会被自 动删除
Exchange – 消息交换机,它指定消息按什么规则,路由到哪个队列。 – Exchange有4种类型:direct(默认),fanout, topic, 和headers,不同类型 的Exchange转发消息的策略有所区别:
Binding – 将一个特定的 Exchange 和一个特定的 Queue 绑定起来。 – Exchange 和Queue的绑定可以是多对多的关系。
virtual host( vhosts ) – 在rabbitmq server上可以创建多个虚拟的message broker,又叫做 virtual hosts (vhosts) – 每一个vhost本质上是一个mini-rabbitmq server,分别管理各自的 exchange,和bindings – vhost相当于物理的server,可以为不同app提供边界隔离 – producer和consumer连接rabbit server需要指定一个vhost
三、RabbitMQ运行机制:
Pub发消息,消息进入服务器(代理)通过exchang额(路由)由消息的路由键同binding找到对应的消息队列写入,consumer通过connection(里的信道可节省开销实质为多路由复用)。获取消息。
四、RabbitMQ整合:
1. 引入spring-boot-starter-amqp 2. application配置 3. 测试RabbitMQ
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
2.配置application:
spring.rabbitmq.host=192.168.1.106
spring.rabbitmq.username=guest
spring.rabbitmq.password=guest
在测试之前我们先看下springboot自动配置rabbiMq原理:
第一步、搜索RabbitAutoConfiguration看里边的内容,主要有:
/**
*探索。rabbitmq的自动配置原理
* 1.RabbitAutoConfiguration
* 2.里面有自动的连接工厂,@ConfigurationProperties(prefix = "spring.rabbitmq")。
* RabbitProperties里面封装了配置的属性
* 3.RabbitTemplate发送接收消息
* 4.AmqpAdmin系统管理组件,声明队列。交换器等
*
*/
3,。测试:
package com.rabbitmq.springbootrabbitmqs;
import com.rabbitmq.springbootrabbitmqs.bean.Book;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.omg.CORBA.PUBLIC_MEMBER;
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 javax.xml.bind.SchemaOutputResolver;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
@RunWith(SpringRunner.class)
@SpringBootTest
public class SpringbootRabbitmqsApplicationTests {
@Autowired
RabbitTemplate rabbitTemplate;
@Test
public void contextLoads() {
//Message 需要自己构造;定义消息体内容和消息头
Map<String,Object>map=new HashMap<>();
map.put("msg","这是第一个消息");
map.put("data", Arrays.asList("hellow",123,true));
//路由名+路邮键+要发送的消息
rabbitTemplate.convertAndSend("exchange.dircett","demo",new Book("西游记","吴承恩"));
}
/**
* 接收数据
* 收到消息之后消息队列里就没有这个消息了
*/
@Test
public void recive(){
//demos是消息队列的名字
Object o=rabbitTemplate.receiveAndConvert("demo");
//打印得到的类型
System.out.println(o.getClass());
System.out.println(o);
;
}
}
测试之前如果要获得json数据需要自定义config:
通过查看RabbitTemplate发现MessageConverter(消息转化器)点击去发现是个接口,ctrl+h发现其现,在其抽象实现中发现有转json的实现,接下来我们编写config
package com.rabbitmq.springbootrabbitmqs.config;
import org.springframework.amqp.core.AmqpAdmin;
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;
/**
* 数据转化json发送出去
* 1.进入RabbitTemplate看MessageConverter(消息转化器)
*
*/
@Configuration
public class MyAMQPConfig {
@Bean
public MessageConverter messageConverter(){
return new Jackson2JsonMessageConverter();
}
}
new Jackson2JsonMessageConverter();并且rerturn。
基本上就可以了。如果要使用监听功能则需要在启动类上加上注解:
package com.rabbitmq.springbootrabbitmqs;
import org.springframework.amqp.rabbit.annotation.EnableRabbit;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
*探索。rabbitmq的自动配置原理
* 1.RabbitAutoConfiguration
* 2.里面有自动的连接工厂,@ConfigurationProperties(prefix = "spring.rabbitmq")。
* RabbitProperties里面封装了配置的属性
* 3.RabbitTemplate发送接收消息
* 4.AmqpAdmin系统管理组件,声明队列。交换器等
*@EnableRabbit开启基于注解的RabbitMq模式
*/
@EnableRabbit
@SpringBootApplication
public class SpringbootRabbitmqsApplication {
public static void main(String[] args) {
SpringApplication.run(SpringbootRabbitmqsApplication.class, args);
}
}
并编写对应的service:
package com.rabbitmq.springbootrabbitmqs.service;
import com.rabbitmq.springbootrabbitmqs.bean.Book;
import com.sun.scenario.effect.impl.sw.sse.SSEBlend_SRC_OUTPeer;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.SocketUtils;
@Service
public class BookService {
@Autowired
RabbitTemplate rabbitTemplate;
@RabbitListener(queues = "hotnews")
public void recive(Book book){
System.out.println("收到消息"+book);
}
@RabbitListener(queues = "suquan")
public void recive02(Message message){
System.out.println(message.getBody());
System.out.println(message.getMessageProperties());
}
}
service层加上 @RabbitListener 第一个方法是获得book信息,第二个是获得消息体,消息头。
如果想添加消息交换机,队列,和绑定规则也很简单:
@Autowired AmqpAdmin amqpAdmin; @Test public void creatExchange(){ // amqpAdmin.declareExchange(new DirectExchange("amqpadmin.exchange")); //队列名字和是否持久化 // amqpAdmin.declareQueue(new Queue("amqpadmin.queue",true)); //绑定规则,目的地,类型;队列,给哪个exchange绑定,路由键:haha,路由参数没有就写null amqpAdmin.declareBinding(new Binding("amqpadmin.queue",Binding.DestinationType.QUEUE,"amqpadmin.exchange","hahha",null)); }
注入AmqpAdmin,编写交换器时候使用的是接口的实现默认传入一个交换器名,队列时候传入队列名,和是否持久化,绑定规则,有目的地,类型,路由键,参数.....