springboot高级篇(消息队列)

1,消息队列

1.1应用场景

大多数应用中,可通过消息服务中间件来提升系统异步通信,扩展解耦能力

1.2,主要内容

1.2.1异步处理

等同于注册用户将注册信息写入数据库,再以极短的时间写入消息队列。立马就可以返回消息给用户。然后发送邮件和发送短信的这些操作。再通过异步从消息队列中读取信息,进行操作

1.2.2应用解耦

订单系统–消息队列–库存系统

1.2.3流量削锋

比如10万个请求直接访问数据库不行,就让他直接访问消息队列。消息队列可设置它最多处理1万条信息。将其余9万条挡掉,秒杀失败。然后再处理秒杀业务

1.3,重要概念

message 消息
destination 目的地

点对点模式:
消息只有唯一的发送者和接受者。但并不是只有一个接收者。
同一时间,一个发送者发送消息到消息队列。多个消费者可以享受接收这个消息的权利。但只能有一个消费者消费这条信息

发布订阅模式:
发布者发送消息到topic。多个接收者订阅这主题。接收者能同时收到消息

1.4 消息服务规范

jms
基于JVM消息代理的规范,不能跨平台跨语言的。activeMq

AMQP
高级消息队列协议,兼容JMS的,rabbitmq是AMQP的实现
跨平台,跨语言。发送数据都是以byte[]将消息序列化后发送
rabbitmq的springboot starter是 spring-boot-starter-amqp

1.5 rabbitMQ

1.5.1核心概念

message
消息:由消息头和消息体组成

publisher
消息的生产者,也是将message发送至Exchange

Exchange
交换器:用于接收生产者发送的消息并将这些消息路由给服务器的队列

Queue
队列:保存消息直到发送给消费者

Binding
绑定:路由键将交换器和队列连接起来的路由规则

connection
网络连接:比如tcp连接

channel
信道:发送数据,订阅队列,接受消息的通道

1.5.2,整个流程

amqp跟jms的差别就是多了binding跟exchange
exchange有四种策略:direct,fanout,topic和headers,只有header不是通过路由键绑定,而是通过消息头

1.5.2.1

1,direct:转发,交换器的key和queue的key相同才会转发
2,fanout:交换器是fanout则广播所有绑定的队列
3,topic是模糊匹配。exchange是路由键和绑定键的单词切分以.分隔。而queue是以#(匹配0或者多个单词)。*(匹配一个单词)。。例如:usa.news 匹配queue中的usa.#

1.5.3,安装,使用,项目

1,hub.docker.com

2,docker pull rabbitmq:3.7.26-management

3,docker run -d -p 5672:5672 -p 15672:15672 --name myrabbitmq rabbitmq:3.7.26-management

4,进入图形化界面,创建交换器:exchange.direct,exchange.fanout,exchange.topic

5,创建队列:atguigu,atguigu.news,atguigu.emps,gulixueyuan.news

6,回到exchange绑定路由键和queue (1)direct:queue:atguigu。rounting key:atguigu queue:atguigu.news routing key:atguigu.news queue:atguigu.emps routing key:atguigu.emps queue:gulixueyuan.news routing key:gulixueyuan.news #(2)fanout 交换器也是绑定这四个queue (3)topic queue:atguigu rounting key:atguigu.# (atguigu开头的routing key绑定atguigu.# new结尾的绑定 *.news一共绑5个)

7,测试direct
publish message选项填写routing key=atguigu payload为发送消息的内容随便写,点击发送。发现就一条队列收到消息,并且精确匹配。到atguigu

8,测试fanout
全收到消息

9,测试topic
routing key=atguigu.news 由于规则匹配atguigu.#和*.news的队列都能发过去。所以这边全部发过去

10,queue可以点击get message按钮获取到发送过来的消息,默认是nack。。。就接受一条发送过来的消息。如果选择ack,则删除掉本条消息,再获取下一条消息

11,项目整合rabbitmq

11.1,创建一个springboot项目,

1,

  <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-amqp</artifactId>
            <version>2.1.13.RELEASE</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind -->
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>2.9.5</version>
        </dependency>

2,

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

3,test类

package com.atguigu.springboot02amqp;
import org.junit.Test;
import org.junit.runner.RunWith;
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.HashMap;
import java.util.Map;

@SpringBootTest
@RunWith(SpringRunner.class)
public class Springboot02AmqpApplicationTests {
    @Autowired
    RabbitTemplate rabbitTemplate;
    @Test
    public void contextLoads() {
      //点对点模式
        //rabbitmq有两种方法消息的方法
        //1,rabbitTemplate.send(exChange,routekey,message)
        //2,rabbitTemplate.covertAndSend(exchange,routekey,Object)

        Map<String,Object>map=new HashMap<>();
        map.put("msg","这是第一个消息");
        map.put("data", Arrays.asList("helloworld",123,true));
        rabbitTemplate.convertAndSend("exchange.direct","atguigu.news",map);


    }

}

这时候直接去rabbit里面去get消息。发现是序列化策略不对的

4,test类继续

写一个receive的方法


  @Test
    public void receive(){
        Object o=rabbitTemplate.receiveAndConvert("atguigu.news");
        System.out.println(o.getClass());
        System.out.println(o);
    }


发现可以读取到控制台。并且消费了消息。但是图形化界面的序列化机制有些不对。怎么改成json的
5,config

package com.atguigu.springboot02amqp.config;

import org.springframework.amqp.core.Message;
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 {
    @Bean
    public MessageConverter messageConverter(){
        return new Jackson2JsonMessageConverter();
    }
}

6,这下发送消息和取消息都正常了

7,rabbitmq操作java-bean

package com.atguigu.springboot02amqp.bean;

public class Book {
    private String bookName;
    private String author;
    Book(){}
    public Book(String bookName, String author) {
        this.bookName = bookName;
        this.author = author;
    }

    public String getBookName() {
        return bookName;
    }

    public void setBookName(String bookName) {
        this.bookName = bookName;
    }

    public String getAuthor() {
        return author;
    }

    public void setAuthor(String author) {
        this.author = author;
    }

    @Override
    public String toString() {
        return "Book{" +
                "bookName='" + bookName + '\'' +
                ", author='" + author + '\'' +
                '}';
    }
}

修改test类

package com.atguigu.springboot02amqp;
import com.atguigu.springboot02amqp.bean.Book;
import org.junit.Test;
import org.junit.runner.RunWith;
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.HashMap;
import java.util.Map;

@SpringBootTest
@RunWith(SpringRunner.class)
public class Springboot02AmqpApplicationTests {
    @Autowired
    RabbitTemplate rabbitTemplate;
    @Test
    public void contextLoads() {
      //点对点模式
        //rabbitmq有两种方法消息的方法
        //1,rabbitTemplate.send(exChange,routekey,message)
        //2,rabbitTemplate.covertAndSend(exchange,routekey,Object)

        Map<String,Object>map=new HashMap<>();
        map.put("msg","这是第一个消息");
        map.put("data", Arrays.asList("helloworld",123,true));
        rabbitTemplate.convertAndSend("exchange.direct","atguigu.news",new Book("java 8新特性","ljs"));


    }

    @Test
    public void receive(){
        Object o=rabbitTemplate.receiveAndConvert("atguigu.news");
        System.out.println(o.getClass());
        System.out.println(o);
    }

}

8,广播队列(不用管rountkey)
修改test类

9,生产者消费者监听问题

9.1,创建service
package com.atguigu.springboot02amqp.service;

import com.atguigu.springboot02amqp.bean.Book;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Service;

@Service
public class BookService {
    @RabbitListener(queues = "atguigu.news")
    public void receive(Book book){
        System.out.println("收到消息:"+book);
    }
}

9.2,启动类加@EnableRabbit
9.3启动项目
9.4,使用单元测试再发一条消息到消息队列
9.5,回到项目发现控制台监听到消息
9.6,如果既想接受到消息,又想获得消息头,新增方法service里
 @RabbitListener(queues = "atguigu")
    public void receive02(Message message){
        System.out.println(message.getBody());
        System.out.println(message.getMessageProperties());
    }

10,以上是本来rabbitMQ已经创建好了exchange和queue。如果没创建。则使用AmqpAdmin操作消息
test类

  //创建exchange
    @Test
    public void createExchange(){
        amqpAdmin.declareExchange(new DirectExchange("amqpadmin.exchange"));
        System.out.println("创建交换器完成");
    }

    //创建queue
    @Test
    public void createQueue(){
        amqpAdmin.declareQueue(new Queue("amqpadmin.queue",true));
    }

    //将创建出的交换器跟队列绑定
    @Test
    public void binding(){
        amqpAdmin.declareBinding(new Binding("amqpadmin.queue",Binding.DestinationType.QUEUE,"amqpadmin.exchange","amqp:haha",null));
    }

exchange参数:指定名称,是否持久化,是否自动删除。queue一样。binding:从左到右:绑定的队列名称,绑定队列,exchange名称,路由键随便写,消息可以指定null

#####rabbitMQ的自动配置
1,rabbitAutoConfiguration
2,有自动配置了连接工厂ConnectionFactory
3,rabbitProperties封装了rabbitMQ的配置
4,rabbitTemplate,给rabbitMq发送和接受消息
5,AmqpAdmin:rabbitMq系统管理功能组件

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值