SpringBoot——消息

一、消息服务的基本概念

1、消息服务中两个重要概念:
消息代理(message broker,消息服务器)和目的地(destination)当消息发送者发送消息以后,将由消息代理接管,消息代理保证消息传递到指定目的地。

2、消息队列主要有两种形式的目的地:

(1) 队列(queue):点对点消息通信(point-to-point)。

  • 发送者发送消息,消息代理将其放入一个队列中,在合适的时候,消息接收者从队列中获取消息内容。

(2) 主题(topic):发布(publish)/订阅(subscribe)消息通信。

  • 发送者发送消息到主题,多个接收者订阅这个主题,那么就会在消息到达时,同时收到消息。

3、消息队列主要可以完成:
(1)异步处理
应用请求不用依次进行处理,提升整体系统的吞吐能力。
在这里插入图片描述

(2)应用间解耦
应用间进行关联时,无需植入过多的接口,能够极大的减少耦合程度。
在这里插入图片描述

(3)流量削峰
当处理秒杀类业务时,能够让后端服务器依据自己的能力来处理业务,可以在一定程度上减少服务器的压力,防止冲垮服务器。
在这里插入图片描述
4、消息服务协议规范

(1)JMS(Java Message Service)JAVA消息服务

  • Java API
  • JMS 定义了JAVA API层面的标准;在java体系中,多个clien均可以通过JMS进行交互,不需要应用修改代码,但是其对跨平台的支持较差。
  • 基于JVM消息代理的规范,ActiveMQ、HornetMQ是JMS实现。

(2)AMQP(Advanced Message Queuing Protocol)

  • 网络级协议
  • 高级消息队列协议,也是一个消息代理的规范,兼容JMS
  • AMQP定义了wire-level层的协议标准;天然具有跨平台、跨语言特性。
  • RabbitMQ是AMQP的实现。

(3)JMS和AMQP对比

JMSAMQP
定义Java API网络级协议
是否跨平台/语言
消息模型(1)点对点
(2)发布/订阅
(1)direct exchange
(2)fanout exchange
(3)topic change
(4)headers exchange
(5)system exchange
后四种和JMS的pub/sub模型没有太大差别,仅是在路由机制上做了更详细的划分;
支持消息类型TextMessage、
MapMessage、
BytesMessage、
StreamMessage、
ObjectMessage、
Message (只有消息头和属性)
byte[] 当实际应用时,有复杂的消息,可以将消息序列化后发送。

5、Spring对消息服务的支持

  • spring-jms提供了对JMS的支持
  • spring-rabbit提供了对AMQP的支持 需要ConnectionFactory的实现来连接消息代理
  • 提供JmsTemplate、RabbitTemplate来发送消息
  • @JmsListener(JMS)、@RabbitListener(AMQP)注解在方法上监听消息代理发布的消息
  • @EnableJms、@EnableRabbit开启支持

6、SpringBoot对消息服务的配置

  • JmsAutoConfiguration
  • RabbitAutoConfiguration

二、AMQP实现——RabbitMQ

RabbitMQ是一个基于erlang语言开发的AMQP(Advanved Message Queue Protocol)开源实现。

1、基本概念

(1)Message
消息由消息头和消息体组成。消息体是不透明的,而消息头则由一系列的可选属性组成,这些属性包括routing-key(路由键)、priority(相对于其他消息的优先权)、delivery-mode(指出该消息可能需要持久性存储)等。

(2)Publisher
消息的生产者,是一个向交换器发布消息的客户端应用程序。

(3)Exchange
服务器中的交换器,用来接收生产者发送的消息并将这些消息路由给服务器中的队列,交换器决定了消息的去向。Exchange有4种类型:direct(默认),fanout, topic, 和headers。

(4)Queue
消息队列,用来保存消息。它是消息的容器,也是消息的终点。一个消息可投入一个或多个队列。消息在队列里面,等待消费者连接到这个队列将其取走。

(5)Binding
绑定,用于消息队列和交换器之间的关联。绑定就是用路由键将交换器和消息队列连接起来的路由规则。Exchange 和Queue的绑定可以是多对多的关系。

(6)Connection
网络连接,比如一个TCP连接。

(7)Channel
信道,多路复用连接中的一条独立的双向数据流通道。信道是建立在真实的TCP连接内的虚拟连接,AMQP 命令都是通过信道发出去的,不管是发布消息、订阅队列还是接收消息,这些动作都是通过信道完成。因为对于操作系统来说建立和销毁TCP 都是非常昂贵的开销,所以引入了信道的概念,以复用一条TCP 连接。

(8)Consumer
消息的消费者,可以从消息队列中取得消息的客户端应用程序。

(9)Virtual Host
虚拟主机,表示一批交换器、消息队列和相关对象。虚拟主机是共享相同的身份认证和加密环境的独立服务器域。每个vhost 本质上就是一个mini 版的RabbitMQ 服务器,拥有自己的队列、交换器、绑定和权限机制。vhost 是AMQP 概念的基础,必须在连接时指定,
RabbitMQ 默认的vhost 是/

(10)Broker
表示消息队列服务器实体
在这里插入图片描述

2、RabbitMQ的运行机制

(1)AMQP 中的消息路由
AMQP 中消息的路由过程和Java 开发者熟悉的JMS 存在一些差别,AMQP 中增加了Exchange 和Binding 的角色。生产者把消息发布到Exchange 上,而Binding 决定交换器的消息应该发送到那个队列。

(2)Exchange
Exchange分发消息时不同分发策略有所区别,目前共四种类型:direct、fanout、topic、headers 。headers 匹配消息队列通过AMQP 消息的header而不是路由键,目前几乎用不到了。

direct: 消息中的路由键(routing key)需要与队列名完全匹配。

fanout:(发布/订阅) 每个发到fanout 类型交换器的消息都会分到所有绑定的队列上去。fanout 交换器不处理路由键,很像子网广播,每台子网内的主机都获得了一份复制的消息。fanout 类型转发消息是最快的。

topic: 将路由键和某个模式进行匹配。两个通配符:#匹配0个或多个单词,*匹配一个单词。
在这里插入图片描述

3、RabbitMQ安装与测试

(1)拉取RabbitMQ

docker pull 阿里云镜像加速地址/library/rabbitmq:3-management

(2)查看是否安装成功

docker images

在这里插入图片描述

(3)启动RabbitMQ
5672:服务器端口
15672:后台管理界面端口

docker run -d -p 5672:5672 -p 15672:15672 --name myRabbitMQ 92c743b6c055

(4)查看运行的容器
docker ps
在这里插入图片描述
(5)访问后台管理界面
默认用户名/密码为:guest/guest
在这里插入图片描述

(6)测试

1)添加交换器和队列
添加一个新的exchange
在这里插入图片描述
一共添加了三个交换器:
在这里插入图片描述
添加四个队列:
在这里插入图片描述

2)绑定

direct绑定:
在这里插入图片描述
在这里插入图片描述
fanout绑定:
无需绑定路由规则。
在这里插入图片描述

topic绑定:
在这里插入图片描述
3)发送消息测试:
对于队列,只有路由键和队列名完全匹配才可以。
在这里插入图片描述
收到消息:
在这里插入图片描述
在这里插入图片描述
对于fanout,无论路由键是什么,都是以广播的形式发给所有队列:
在这里插入图片描述
对于主题:
只有匹配指定路由规则的队列才可以收到消息,这里只有cbj.news和glp.news可以收到消息。
在这里插入图片描述

4、SpringBoot和RabbitMQ整合

RabbitAutoConfiguration
RabbitProperties:封装了RabbitMQ的配置
RabbitTemplate:给RabbitMQ发送和接收消息
AmqpAdmin :系统管理功能组件

(1)引入依赖

<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-amqp</artifactId>
</dependency>

(2)application.properties配置

spring.rabbitmq.host=47.94.230.49
spring.rabbitmq.username=guest
spring.rabbitmq.password=guest

(3)测试RabbitMQ
发送消息/接收消息

  • send(exchange,routekey,message);使用send发送消息,message需要自己构建(包括消息头和消息体)
  • convertAndSend(exchange,routeKey,object):object默认作为消息体,并且会自动序列化发送给Rabbitmq.

在这里插入图片描述

RabbitMQ管理界面得到的数据:
在这里插入图片描述

RabbitTemplate在处理消息时,默认使用SimpleMessageConverter():
在这里插入图片描述
在RabbitAutoConfiguration中配置RabbitTemplate时,可以从容器中导入自己的MessageConverter:
在这里插入图片描述
(4)自定义一个MessageConverter

@Configuration
public class myAMQPConfig { 
    @Bean
    public MessageConverter myMessageconverter(){
       return new Jackson2JsonMessageConverter();
    }
}

配置完消息转换器之后:
在这里插入图片描述
(5)监听消息列表
监听消息列表,实时接收消息
使用@RabbitListener来监听消息,需要开启Rabbit相关的注解@EnableRabbit

在主启动类上加上注解:@EnableRabbit
在这里插入图片描述
可以利用Message获取消息体以及消息头
在这里插入图片描述
(6)在Java程序中创建Exchange、队列以及绑定规则
AmqpAdmin:管理组件,用来创建Exchange,Queue,Binding

创建Exchange:
在这里插入图片描述
创建队列:

在这里插入图片描述
创建绑定关系:

Binding(
String destination, 要绑定的目的地
Binding.DestinationType destinationType, 目的地类型
String exchange, 交换器
String routingKey, 路由规则
@Nullable Map<String, Object> arguments 参数
)

在这里插入图片描述

三、JMS实现——ActiveMQ

ActiveMQ下载::http://activemq.apache.org/

1、队列发送者

(1)新建一个springboot工程
(2)导入依赖

<dependency>    
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-web</artifactId> 
</dependency>

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-activemq</artifactId> 
</dependency>

(3)配置application.yml

server:
  port: 6666

spring:
  activemq:  
    broker-url: tcp://192.168.0.110:61616 # 自己的MQ服务器地址  
    user: admin  
    password: admin
  jms:  
    pub-sub-domain: false      
    #false = Queue   true = Topic
    
# 队列名称
myqueue: springboot-activemq-queue

(4)ActiveMQ配置Bean

@Configuration
@EnableJms // 声明对 JMS 注解的支持。 
public class ActiveMQConfig {    
	@Value("${myqueue}")    
	private String myqueue;
	
    @Bean    
    public Queue queue(){        
  	  return new ActiveMQQueue(myqueue);    
    }
}

(5)编写队列的消息生成者

@Component 
public class QueueProduce {
    
    @Autowired    
    private JmsMessagingTemplate template;
   
    @Autowired    
    private Queue queue;
    
    public void produceMsg(){
       template.convertAndSend(queue,"produceMsg"); 
    }
}

扩展:
每隔3秒钟往MQ推送消息,定时发送。

// 带定时功能的 
@Scheduled(fixedDelay = 3000) 
public void produceMsgScheduled(){
    template.convertAndSend(queue,"produceMsgScheduled");
	System.out.println("系统定时投递 produceMsgScheduled"); 
}

在主启动类上也要增加一个对应的支持注解@EnabelScheduling。
在这里插入图片描述
(6)Controller

@RestController
public class ActiveMQController {
    @Autowired    
    private QueueProduce queueProduce;
    
    // 理论每请求一次,都会发送一条消息到队列    
    @RequestMapping("/queue/produce")    
    public void queue_send(){        	
	   	 queueProduce.produceMsg();        
    	 System.out.println("消息发送成功!");    
    }
}
2、队列消费者

(1)消息消费者:

@Configuration 
public class QueueConsumer {
    @JmsListener(destination = "${myqueue}")
    public void receive(TextMessage textMessage) throws JMSException {        
    	System.out.println("消费者收到消息:"+textMessage.getText());    
    }     
}

启动测试,看是否能够收到消息。

3、主题生产者

(1)配置文件
和队列不同的是 jms.pub-sub-domain。

server:
  port: 6666

spring:
  activemq:  
    broker-url: tcp://192.168.0.110:61616 # 自己的MQ服务器地址  
    user: admin  
    password: admin
  jms:  
    pub-sub-domain: true      
    #false = Queue   true = Topic

# 队列名称
myqueue: springboot-activemq-queue
# 主题名称 
mytopic: springboot-activemq-topic

(2)修改配置类

@Configuration
@EnableJms // 声明对 JMS 注解的支持。 
public class ActiveMQConfig {    
	@Value("${myqueue}")    
	private String myqueue;
	
	@Value("${mytopic}")    
	private String mytopic;
    @Bean    
    public Topic queue(){        
  	  return new ActiveMQTopic(mytopic);    
    }
}

(3)主题发布类

@Component
public class TopicProduce{
	@Autowired
	private JmsMessagingTemplate jmsMessagingTemplate;

	@Autowired
	private Topic topic
	
	 @Scheduled(fixedDelay = 3000)    
	 public void produceTopic(){
	     jmsMessagingTemplate.convertAndSend(topic,"=>produceTopic");
	     System.out.println("消息推送完毕");    
	 }
}

注意:
主题发布之前需要现有主题消费者运行起来。

4、主题消费者
@Configuration 
public class QueueConsumer {
    @JmsListener(destination = "${mytopic}")    
    public void receive(TextMessage textMessage) throws JMSException {
       System.out.println("消费者收到主题发布消息:"+textMessage.getText());    
    }
}

启动项目进行测试。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值