SpringBoot与消息

JMS & AMPQ简介

1、消息服务中两个重要的概念:消息代理和目的地

当消息发送者发送消息以后,将由消息代理接管,消息代理保证消息传递到指定目的地

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

  (1) 队列(queue:点对点消息通信,只能有唯一的发送者和接受者,但不一定只能有一个接收者

  (2) 主题(topic: 发布(publish/订阅(subscribe)消息通信,多个接收者监听主题,会在消息到达同时接收到消息

3、JMSJava Message Service):JAVA消息服务,基于JVM消息代理的规范,ActiveMQHornetMQJMS的实现

4、AMQPAdvanced Message Queuing Protocol

  (1) 高级消息队列协议,也是一个消息代理的规范,兼容JMS

  (2) RabbitMQAMQP的实现

 

JMS

AMQP

定义

Java api

Wire-protocol

跨语言

跨平台

Model

提供两种消息模型:

(1)、Peer-2-Peer

(2)、Pub/sub

提供了五种消息模型:

(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[]

当实际应用时,有复杂的消息,可以将消息序列化后发送。

综合评价

JMS 定义了JAVA API层面的标准;在java体系中,多个client均可以通过JMS进行交互,不需要应用修改代码,但是其对跨平台的支持较差;

AMQP定义了wire-level层的协议标准;天然具有跨平台、跨语言特性。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

RabbitMQ简介

RabbitMQ是一个由erlang开发的AMQPAdvanved Message Queue Protocol)的开源实现

基本概念

  • P: 为Producer,数据的发送方,生产者。
  • C:为Consumer,数据的接收方,消费者。
  • Exchange:消息交换机,它指定消息按什么规则,路由到哪个队列。
  • Queue:消息队列载体,每个消息都会被投入到一个或多个队列。
  • Binding:绑定,它的作用就是把exchangequeue按照路由规则绑定起来。
  • Routing Key:路由关键字,exchange根据这个关键字进行消息投递。
  • vhost:虚拟主机,一个broker里可以开设多个vhost,用作不同用户的权限分离。
  • channel:消息通道,在客户端的每个连接里,可建立多个channel,每个channel代表一个会话任务。

RabbitMQ运行机制

AMQP中的消息的路由过程和JMS存在一些差别,AMQP中增加了ExchangeBinding的角色。生产者把消息发布到Exchange上,消息最终到达队列并被消费者接收,而Binding决定交换器的消息应该发送到哪个队列

 

Exchange类型:

Exchange分发消息时根据类型的不同分发策略有区别,目前共有四种类型:directfanouttopicheaders。其中headers不是使用路由键匹配AMQP消息。且headers交换器和direct交换器完全一致,但是性能差很多,目前几乎用不到了

整合RabbitMQ

创建项目,选中RabbitMQ模块

配置RabbitMQ

在配置文件中配置rabbitMQ

spring:
  rabbitmq:
    host: 172.17.119.176
    username: guest
    password: guest
    port: 5672
#    virtual-host:

使用RabbitTemplate操作消息

@Autowired
RabbitTemplate rabbitTemplate;


@Test
public void contextLoads() {
    // Message: 需要自己构造一个消息,定义消息体内容和消息头
    // rabbitTemplate.send(exchange, routeKey, message);

    // 只需要传入要发送的对象,自动序列化发送,object默认被当做消息体
    // rabbitTemplate.convertAndSend(exchange, routeKey, object);
    Map<String, Object> map = new HashMap<>();
    map.put("msg", "这是一条消息");
    map.put("list", Arrays.asList("hello", 123, true));
    rabbitTemplate.convertAndSend("exchange.direct", "atguigu.news", map);
}

/**
 * 接收消息
 */
@Test
public void receive(){
    Object o = rabbitTemplate.receiveAndConvert("atguigu.news");
    System.out.println(o.getClass());
    System.out.println(o);
}

序列化机制

在发送消息的时候,接收到的数据是按照JDK序列化后的,会显得很乱,就像下面这样:

那么如何将接收到的数据自动转换成json发送出去呢?

其实只需要在配置类中添加我们自己得序列化规则即可

@Bean
public MessageConverter messageConverter(){
    return new Jackson2JsonMessageConverter();
}

在发消息接收到后就是json格式了

 

@RabbitListener & @EnableRabbit

@EnableRabbit + @RabbitListener可以监听消息队列的内容

①、首先要在主程序类上标注@EnableRbbit开启消息监听

@EnableRabbit
@SpringBootApplication
public class RabbitmqApplication {

    public static void main(String[] args) {
        SpringApplication.run(RabbitmqApplication.class, args);
    }
}

②、然后在要监听消息的方法上标注@RabbitListener,并指定要监测的消息队列即可,只要队列接收到了消息就会执行该方法

@RabbitListener(queues = "atguigu.news")  // 监听atguigu.news队列的消息
public void receive(Book book){
    System.out.println("接收消息" + book);
}

还可以使用Message监听消息的头信息和消息体信息

@RabbitListener(queues = "atguigu.news")
public void receive02(Message message){
    // 消息体
    System.out.println(message.getBody());
    // 消息头信息
    System.out.println(message.getMessageProperties());
}

AmqpAdmin管理组件的使用

之前的交换器跟队列都是在rabbitmqweb界面手动创建的

创建Exchange

创建队列:

绑定交换器跟队列:

那么怎样在程序中创建这些呢?

这就需要使用AmqpAdmin去管理RabbitMQ的组件,它可以帮我们创建和删除QueueExchangeBinding

创建交换器:

需要使用DirectExchange去创建,然后使用AmqpAdmin去添加

@Autowired
AmqpAdmin amqpAdmin;

@Test
public void createExchange(){
    amqpAdmin.declareExchange(new DirectExchange("amqpadmin.directexchange"));
}

创建其他的交换器只需要将创建exchange的类换一下即可

删除交换器:

@Test
public void createExchange(){
    amqpAdmin.deleteExchange("amqpadmin.directexchange");
}

创建队列:

@Autowired
AmqpAdmin amqpAdmin;

@Test
public void createQueue(){
//  amqpAdmin.declareQueue();   // 什么都不写会自动生成对列名
    // 第一个参数:队列的名字。第二个参数:是否持久化
    amqpAdmin.declareQueue(new Queue("amqpadmin.queue", true));
}

删除队列:

@Test
public void createQueue(){
    amqpAdmin.deleteQueue("amqpadmin.queue");
}

绑定交换器与队列:

@Autowired
AmqpAdmin amqpAdmin;

@Test
public void bind(){
    /**
     * 参数一:目的地,即要绑定的队列或交换器
     * 参数二:类型,绑定的是队列还是交换器
     * 参数三:交换器的名字
     * 参数四:路由键
     * 参数五:null
     */
    amqpAdmin.declareBinding(new Binding("amqpadmin.queue", Binding.DestinationType.QUEUE, "amqpadmin.directexchange",
            "amqpadmin.haha", null));
}

解绑:

@Autowired
AmqpAdmin amqpAdmin;

@Test
public void bind(){
    /**
     * 参数一:目的地,即要绑定的队列或交换器
     * 参数二:类型,绑定的是队列还是交换器
     * 参数三:交换器的名字
     * 参数四:路由键
     * 参数五:null
     */
    amqpAdmin.removeBinding(new Binding("amqpadmin.queue", Binding.DestinationType.QUEUE, "amqpadmin.directexchange",
                "amqpadmin.haha", null));
}

 

posted @ 2018-09-19 13:55  Jin同学  阅读(144)  评论(0编辑  收藏  举报