SpringAMQP

什么是SpringAMQP

        SpringAMQP_第1张图片

官方网址

官方文档https://spring.io/projects/spring-amqp

Base Queue 简单队列模型

SpringAMQP_第2张图片

 对于生产者

        
        
            org.springframework.boot
            spring-boot-starter-amqp
        
spring:
  rabbitmq:
    port: 5672
    host: 8.130.89.67
    virtual-host: /
    username: itcast
    password: 123
    @Autowired
    private RabbitTemplate template;
    @Test
    public void testSimpleQueue(){
        String queueName="simple.queue";
        String message="hello spring ampq";
        template.convertAndSend(queueName,message);
    }

对于消费者

依赖已经在父工程中到过了

配置和生产者的一样,粘贴过来就行

新建一个类

@Component
public class SpringRabbitListener {
    @RabbitListener(queues = "simple.queue")
    public void listenSimpleQueueMessage(String msg){
        System.out.println("spring 消费者接收到消息 :【" + msg + "】");
    }
}

启动项目就可以消费消息了

因为是消息队列,所以先生产的消息就先被消费。先进先出。

rabbit没有消息回溯功能,一旦被消费就不可逆。

Work Queue 工作队列模型

可以提高消息处理速度,避免队列消息堆积。

SpringAMQP_第3张图片

案例

SpringAMQP_第4张图片 生产者

    @Test
    public void testWorkQueue() throws InterruptedException {
        String queueName="simple.queue";
        String message="hello , message_";
        for(int i=1;i<=50;i++){
            template.convertAndSend(queueName,message+i);
            Thread.sleep(20);
        }
    }

 消费者

配置文件

spring:
  rabbitmq:
    port: 5672
    host: 8.130.89.67
    virtual-host: /
    username: itcast
    password: 123
    listener:
      simple:
        prefetch: 1    # 每次只能获取一条消息,处理完成才能获取下一个消息
    @RabbitListener(queues = "simple.queue")
    public void listenSimpleQueueMessage1(String msg) throws InterruptedException {
        System.out.println("spring 消费者1接收到消息 :【" + msg + "】"+ LocalTime.now());
        Thread.sleep(20);
    }
    @RabbitListener(queues = "simple.queue")
    public void listenSimpleQueueMessage2(String msg) throws InterruptedException {
        System.err.println("spring 消费者2接收到消息 :【" + msg + "】"+LocalTime.now());
        Thread.sleep(200);
    }

启动消费者项目,

SpringAMQP_第5张图片

 可以看到消息的处理时按照生产顺序来的,先进先出。
 

多个消费者绑定到一个队列,同一条消息只会被一个消费者处理

通过配置prefetch来控制消费者预取的消息数量

发布、订阅模型-Fanout

允许将同一消息发送给多个消费者。实现方式是加入了exchange(交换机)。

SpringAMQP_第6张图片

Fanout Exchange 会将接收到的消息广播到每一个跟其绑定的queue。

 消费者

import org.springframework.amqp.core.Binding;
import org.springframework.amqp.core.BindingBuilder;
import org.springframework.amqp.core.FanoutExchange;
import org.springframework.amqp.core.Queue;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class FanoutConfig {
    @Bean
    public FanoutExchange fanoutExchange(){
        return  new FanoutExchange("itcast.fanout");
    }
    @Bean
    public Queue fanoutQueue1(){
        return  new Queue("fanout.queue1");
    }
    @Bean
    public Queue fanoutQueue2(){
        return  new Queue("fanout.queue2");
    }
    @Bean
    public Binding bindingQueue1(Queue fanoutQueue1,FanoutExchange fanoutExchange){
        return BindingBuilder.bind(fanoutQueue1).to(fanoutExchange);
    }
    @Bean
    public Binding bindingQueue2(Queue fanoutQueue2,FanoutExchange fanoutExchange){
        return BindingBuilder.bind(fanoutQueue2).to(fanoutExchange);
    }
}
    @RabbitListener(queues = "fanout.queue1")
    public void listenFanoutQueue1(String msg) throws InterruptedException {
        System.out.println("spring 消费者1接收到消息 :【" + msg + "】");
    }

    @RabbitListener(queues = "fanout.queue2")
    public void listenFanoutQueue2(String msg) throws InterruptedException {
        System.out.println("spring 消费者1接收到消息 :【" + msg + "】");
    }

发布者

    @Test
    public void testFanoutExchange() {
        String exchangeName="itcast.fanout";    //对应消费者的交换机名字
        String message="hello , everyBody";
        template.convertAndSend(exchangeName,"",message);
    }

SpringAMQP_第7张图片

 SpringAMQP_第8张图片

 SpringAMQP_第9张图片

交换机的作用

        接受发布者发布的消息

        将消息按照规则路由到与之绑定的队列

        不能缓存消息,路由失败,消息丢失 

发布、订阅模型-Direct

每一个Queue都与Exchange设置一个BindingKey

发布者发送消息时,指定消息的RoutingKey

Exchange将消息路由到BindingKey与消息RoutingKey一致的队列

SpringAMQP_第10张图片

 消费者

    @RabbitListener(bindings = @QueueBinding(
            value = @Queue(name = "direct queue1"),
            exchange = @Exchange(name = "itcast.direct",type = ExchangeTypes.DIRECT),
            key = {"red","blue"}
    ))
    public void listenDirectQueue1(String msg){
        System.out.println("spring 消费者1接收到消息 :【" + msg + "】");
    }
    @RabbitListener(bindings = @QueueBinding(
            value = @Queue(name = "direct queue2"),
            exchange = @Exchange(name = "itcast.direct",type = ExchangeTypes.DIRECT),
            key = {"red","yellow"}
    ))
    public void listenDirectQueue2(String msg){
        System.out.println("spring 消费者2接收到消息 :【" + msg + "】");
    }

生产者

    @Test
    public void testDirectExchange() {
        String exchangeName="itcast.direct";
        String message="hello , red";
        template.convertAndSend(exchangeName,"red",message);
    }

差异

Direct交换机和Fanout交换机的差异

        Fanout将消息路由给每一个与之绑定的队列

        Direct交换机根据RoutingKey判断路由给哪一个队列

        如果多个队列的RoutingKey相等,则和Fanout功能类似

核心

        @Queue        @Exchange

发布、订阅模型-Topic

TopicExchange与DirectExchange类似,区别在于routingKey,Queue与Exchange指定BindingKey时可以使用通配符:

# :代指0个或多个单词

* :代指一个单词

SpringAMQP_第11张图片

消费者

 

    @RabbitListener(bindings = @QueueBinding(
            value = @Queue(name = "topic queue1"),
            exchange = @Exchange(name = "itcast.topic",type = ExchangeTypes.TOPIC),
            key = {"china.#"}
    ))
    public void listenTopicQueue1(String msg){
        System.out.println("spring 消费者1接收到消息 :【" + msg + "】");
    }
    @RabbitListener(bindings = @QueueBinding(
            value = @Queue(name = "topic queue2"),
            exchange = @Exchange(name = "itcast.topic",type = ExchangeTypes.TOPIC),
            key = {"#.news"}
    ))
    public void listenTopicQueue2(String msg){
        System.out.println("spring 消费者2接收到消息 :【" + msg + "】");
    }

生产者

    @Test
    public void testTopicExchange() {
        String exchangeName="itcast.topic";
        String message="你看到了这句话";
        template.convertAndSend(exchangeName,"Chain.news",message);
    }

差异

Direct交换机与Topic交换机的差异

Topic交换机接收的消息RoutingKey必须是多个单词,以 . 分割

Topic交换机与队列绑定时的bindingKey可以指定通配符

消息转换器

在SpringAMQP的发送方法中,接收消息的类型是Object,也就是说我们可以发送任意对象类型的消息,SpringAMQP会帮我们序列化为字节后发送。

生产者

    @Test
    public void testSimpleQueue(){
        String queueName="simple.queue";
        Map map=new HashMap<>();
        map.put("name","angelababy");
        map.put("sex","woman");
        template.convertAndSend(queueName,map);
    }

Spring的对消息对象的处理是由org.springframework.amqp.support.converter.MessageConverter来处理的。而默认实现是SimpleMessageConverter,基于JDK的ObjectOutputStream完成序列化。 如果要修改只需要定义一个MessageConverter 类型的Bean即可。推荐用JSON方式序列化,

父项目导入依赖

        
            com.fasterxml.jackson.core
            jackson-databind
        

启动类中声明Bean也可以书写配置类,都一样

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

消费者

也是需要声明Bean和生产者一样

    @RabbitListener(queues = "simple.queue")
    public void listenSimpleQueueMessage(Map msg){
        System.out.println("spring 消费者接收到消息 :【" + msg + "】");
    }

需要注意的就是接受消息的参数数据类型修改成Map的

 

你可能感兴趣的:(java,java-rabbitmq,rabbitmq)