Spring RabbitMQ (延时任务)

Spring+RabbitMQ(XML)

目录

1. Simple 1

2. Work Queue 3

3. Publish/Subscribe 4

4. Routing 6

5. Topic 9

6. 消费者手动确认 11

7. Rabbitmq延时队列(死信) 13

  1. Simple
    概:一对一消费

【生产者】

package cn.ywj.simple;

import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class P {

    public static void main(String[] args) {

        ApplicationContext context = new ClassPathXmlApplicationContext("simple/p.xml");
        RabbitTemplate template = context.getBean(RabbitTemplate.class);
        template.convertAndSend("simple-queue", "Hello");
        System.out.println("发送完毕");
    }
}

 

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:rabbit="http://www.springframework.org/schema/rabbit"
       xsi:schemaLocation="http://www.springframework.org/schema/rabbit
           http://www.springframework.org/schema/rabbit/spring-rabbit.xsd
           http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans.xsd">

    <!--工厂类-->
    <rabbit:connection-factory id="connectionFactory" virtual-host="/" host="127.0.0.1" username="guest" password="guest"/>
    <!--消息模样-->
    <rabbit:template id="rabbitTemplate" connection-factory="connectionFactory"/>
    <!--管理-->
    <rabbit:admin connection-factory="connectionFactory"/>
    <!--队列-->
    <rabbit:queue name="simple-queue"/>
</beans>

【消费者】

package cn.ywj.simple;

import org.springframework.context.support.ClassPathXmlApplicationContext;

public class C {

    public static void main(String[] args) {

        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("simple/c.xml");
        context.start();
    }
}

 

package cn.ywj.simple;

import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessageListener;

public class O implements MessageListener {

    @Override
    public void onMessage(Message message) {
        System.out.println("[O] "+new String(message.getBody()));
    }
}

 

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:rabbit="http://www.springframework.org/schema/rabbit"
       xsi:schemaLocation="http://www.springframework.org/schema/rabbit
           http://www.springframework.org/schema/rabbit/spring-rabbit.xsd
           http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans.xsd">

    <!--工厂类-->
    <rabbit:connection-factory id="connectionFactory" virtual-host="/" host="127.0.0.1" username="guest" password="guest"/>
    <!--消息模样-->
    <rabbit:admin connection-factory="connectionFactory"/>
    <!--管理-->
    <rabbit:queue name="simple-queue"/>
    <!--接收的消息处理的对象-->
    <bean id="o" class="cn.ywj.simple.O"/>
    <!--消息监听绑定-->
    <rabbit:listener-container connection-factory="connectionFactory">
        <rabbit:listener ref="o" queues="simple-queue"/>
    </rabbit:listener-container>

</beans>

 

  1. Work Queue
    概:一对多消费,多瓜分一

【消费者】

相对于Simple模式多了个rabbit:listener

<!--接收的消息处理的对象-->
<bean id="o" class="cn.ywj.simple.O"/>
<bean id="o2" class="cn.ywj.simple.O2"/>

<!--消息监听绑定-->
<rabbit:listener-container connection-factory="connectionFactory">
    <rabbit:listener ref="o" queues="simple-queue"/>
    <rabbit:listener ref="o2" queues="simple-queue"/>
</rabbit:listener-container>

或者

<!--接收的消息处理的对象-->
<bean id="o" class="cn.ywj.simple.O"/>
<bean id="o2" class="cn.ywj.simple.O2"/>

<!--消息监听绑定-->
<!--prefetch:每次接收多个少-->
<rabbit:listener-container connection-factory="connectionFactory" prefetch="1">
    <rabbit:listener ref="o" queues="simple-queue"/>
</rabbit:listener-container>

<rabbit:listener-container connection-factory="connectionFactory" prefetch="2">
    <rabbit:listener ref="o2" queues="simple-queue"/>
</rabbit:listener-container>

  1. Publish/Subscribe
    概:一对多消费,多独立对一

【生产者】

package cn.ywj.faoutExchange;

import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class P {

    public static void main(String[] args) {

        ApplicationContext context = new ClassPathXmlApplicationContext("faoutExchange/p.xml");
        RabbitTemplate template = context.getBean(RabbitTemplate.class);
        template.convertAndSend("faout-exchange", null,"Hello Title");
        System.out.println("发送完毕");
    }
}

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:rabbit="http://www.springframework.org/schema/rabbit"
       xsi:schemaLocation="http://www.springframework.org/schema/rabbit
           http://www.springframework.org/schema/rabbit/spring-rabbit.xsd
           http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans.xsd">

    <!--工厂类-->
    <rabbit:connection-factory id="connectionFactory" virtual-host="/" host="127.0.0.1" username="guest" password="guest"/>
    <!--消息模样-->
    <rabbit:template id="rabbitTemplate" connection-factory="connectionFactory"/>
    <!--管理-->
    <rabbit:admin connection-factory="connectionFactory"/>
    <!--队列-->
    <rabbit:queue name="faout-exchange-queue-1"/>
    <rabbit:queue name="faout-exchange-queue-2"/>

    <rabbit:fanout-exchange name="faout-exchange"><!--faout.exchange交换机的名字-->
        <rabbit:bindings>
            <!-- 绑定的队列,不绑定或队列不存在消息会丢失,交换机不负责保存数据-->
            <rabbit:binding queue="faout-exchange-queue-1" />
            <rabbit:binding queue="faout-exchange-queue-2" />
        </rabbit:bindings>
    </rabbit:fanout-exchange>
</beans>

【消费者】

package cn.ywj.faoutExchange;

import org.springframework.context.support.ClassPathXmlApplicationContext;

public class C {

    public static void main(String[] args) {

        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("faoutExchange/c.xml");
        context.start();
    }
}

package cn.ywj.faoutExchange;

import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessageListener;

public class O implements MessageListener {

    @Override
    public void onMessage(Message message) {
        System.out.println("[O] "+new String(message.getBody()));
    }
}

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:rabbit="http://www.springframework.org/schema/rabbit"
       xsi:schemaLocation="http://www.springframework.org/schema/rabbit
           http://www.springframework.org/schema/rabbit/spring-rabbit.xsd
           http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans.xsd">

    <!--工厂类-->
    <rabbit:connection-factory id="connectionFactory" virtual-host="/" host="127.0.0.1" username="guest" password="guest"/>
    <!--消息模样-->
    <rabbit:admin connection-factory="connectionFactory"/>
    <!--管理-->
    <rabbit:queue name="faout-exchange-queue-1"/>
    <rabbit:queue name="faout-exchange-queue-2"/>

    <!--接收的消息处理的对象-->
    <bean id="o" class="cn.ywj.faoutExchange.O"/>
    <bean id="o2" class="cn.ywj.faoutExchange.O2"/>

    <!--消息监听绑定-->
    <!--prefetch:每次接收多个少-->
    <rabbit:listener-container connection-factory="connectionFactory">
        <rabbit:listener ref="o" queues="faout-exchange-queue-1"/>
        <rabbit:listener ref="o2" queues="faout-exchange-queue-2"/>
    </rabbit:listener-container>

</beans>

  1. Routing

概:匹配消费

【生产者】

package cn.ywj.routing;

import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class P {

    public static void main(String[] args) {

        ApplicationContext context = new ClassPathXmlApplicationContext("routing/p.xml");
        RabbitTemplate template = context.getBean(RabbitTemplate .class);
        template.convertAndSend("color.exchange", "color.black", "Hello Black");
        template.convertAndSend("color.exchange", "color.white", "Hello White");
        template.convertAndSend("color.exchange", "color.red", "Hello Red");
        template.convertAndSend("color.exchange", "color.blue", "Hello Blue");
        System.out.println("发送完毕");

    }
}

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:rabbit="http://www.springframework.org/schema/rabbit"
       xsi:schemaLocation="http://www.springframework.org/schema/rabbit
           http://www.springframework.org/schema/rabbit/spring-rabbit.xsd
           http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans.xsd">

    <!--工厂类-->
    <rabbit:connection-factory id="connectionFactory" virtual-host="/" host="127.0.0.1" username="guest" password="guest"/>
    <!--消息模样-->
    <rabbit:template id="amqpTemplate" connection-factory="connectionFactory"/>
    <!--管理-->
    <rabbit:admin connection-factory="connectionFactory"/>
    <!--队列-->
    <rabbit:queue name="blackQueue"/>
    <rabbit:queue name="whiteQueue"/>
    <rabbit:queue name="red-blue-Queue"/>

    <rabbit:direct-exchange name="color.exchange">
        <rabbit:bindings>
            <rabbit:binding queue="blackQueue" key="color.black"/>
            <rabbit:binding queue="whiteQueue" key="color.white"/>
            <rabbit:binding queue="red-blue-Queue" key="color.red"/>
            <rabbit:binding queue="red-blue-Queue" key="color.blue"/>
        </rabbit:bindings>
    </rabbit:direct-exchange>
</beans>

【消费者】

package cn.ywj.routing;

import org.springframework.context.support.ClassPathXmlApplicationContext;

public class C {

    public static void main(String[] args) {

        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("routing/c.xml");
        context.start();
    }
}

package cn.ywj.routing;

public class O {

    public void black(String msg){
        System.out.println("[black]:"+msg);
    }

    public void white(String msg){
        System.out.println("[white]:"+msg);
    }

    public void red_blue(String msg){
        System.out.println("[red_blue]:"+msg);
    }
}

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:rabbit="http://www.springframework.org/schema/rabbit"
       xsi:schemaLocation="http://www.springframework.org/schema/rabbit
           http://www.springframework.org/schema/rabbit/spring-rabbit.xsd
           http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans.xsd">
    <!--工厂类-->
    <rabbit:connection-factory id="connectionFactory" virtual-host="/" host="127.0.0.1" username="guest" password="guest"/>
    <!--消息模样-->
    <rabbit:admin connection-factory="connectionFactory"/>
    <!--管理-->
    <rabbit:queue name="blackQueue"/>
    <rabbit:queue name="whiteQueue"/>
    <rabbit:queue name="red-blue-Queue"/>

    <!--接收的消息处理的对象-->
    <bean id="o" class="cn.ywj.routing.O"/>

    <!--消息监听绑定-->
    <rabbit:listener-container connection-factory="connectionFactory">
        <rabbit:listener ref="o" method="black" queues="blackQueue"/>
        <rabbit:listener ref="o" method="white" queues="whiteQueue"/>
        <rabbit:listener ref="o" method="red_blue" queues="red-blue-Queue"/>
    </rabbit:listener-container>

</beans>

  1. Topic

概:类似模糊匹配消费

package cn.ywj.topic;

import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class P {

    public static void main(String[] args) {

        ApplicationContext context = new ClassPathXmlApplicationContext("topic/p.xml");
        RabbitTemplate template = context.getBean(RabbitTemplate .class);
        template.convertAndSend("topic-exchange", "hello", "Hello");
        template.convertAndSend("topic-exchange", "hello.1", "Hello.1");
        template.convertAndSend("topic-exchange", "hello.1.2", "Hello 1 2");
        template.convertAndSend("topic-exchange", "hello.1.2.3", "Hello 1 2 3");
        template.convertAndSend("topic-exchange", "0.hello.1.2", "0 Hello 1 2");
        System.out.println("发送完毕");

    }
}

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:rabbit="http://www.springframework.org/schema/rabbit"
       xsi:schemaLocation="http://www.springframework.org/schema/rabbit
           http://www.springframework.org/schema/rabbit/spring-rabbit.xsd
           http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans.xsd">

    <!--工厂类-->
    <rabbit:connection-factory id="connectionFactory" virtual-host="/" host="127.0.0.1" username="guest" password="guest"/>
    <!--消息模样-->
    <rabbit:template id="amqpTemplate" connection-factory="connectionFactory"/>
    <!--管理-->
    <rabbit:admin connection-factory="connectionFactory"/>
    <!--队列-->
    <rabbit:queue name="one-queue"/>
    <rabbit:queue name="zero-more-queue"/>
    <rabbit:queue name="more-one-queue"/>

    <rabbit:topic-exchange name="topic-exchange">
        <rabbit:bindings>
            <!--
            * (star) can substitute for exactly one word.
            # (hash) can substitute for zero or more words.
            -->
            <rabbit:binding pattern="#.hello.*" queue="more-one-queue"></rabbit:binding>
            <rabbit:binding pattern="hello.*" queue="one-queue"></rabbit:binding>
            <rabbit:binding pattern="hello.#" queue="zero-more-queue"></rabbit:binding>
        </rabbit:bindings>
    </rabbit:topic-exchange>
</beans>

【消费者】

package cn.ywj.topic;

import org.springframework.context.support.ClassPathXmlApplicationContext;

public class C {

    public static void main(String[] args) {

        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("topic/c.xml");
        context.start();
    }
}

package cn.ywj.topic;

public class O {

    public void one(String msg){
        System.out.println("[one]:"+msg);
    }

    public void zero_more(String msg){
        System.out.println("[zero_more]:"+msg);
    }

    public void more_one(String msg) {
        System.out.println("[more_one]:"+msg);
    }
}

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:rabbit="http://www.springframework.org/schema/rabbit"
       xsi:schemaLocation="http://www.springframework.org/schema/rabbit
           http://www.springframework.org/schema/rabbit/spring-rabbit.xsd
           http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans.xsd">
    <!--工厂类-->
    <rabbit:connection-factory id="connectionFactory" virtual-host="/" host="127.0.0.1" username="guest" password="guest"/>
    <!--消息模样-->
    <rabbit:admin connection-factory="connectionFactory"/>
    <!--管理-->
    <rabbit:queue name="one-queue"/>
    <rabbit:queue name="zero-more-queue"/>
    <rabbit:queue name="more-one-queue"/>

    <!--接收的消息处理的对象-->
    <bean id="o" class="cn.ywj.topic.O"/>

    <!--消息监听绑定-->
    <rabbit:listener-container connection-factory="connectionFactory">
        <rabbit:listener ref="o" method="one" queues="one-queue"/>
        <rabbit:listener ref="o" method="zero_more" queues="zero-more-queue"/>
        <rabbit:listener ref="o" method="more_one" queues="more-one-queue"/>
    </rabbit:listener-container>

</beans>

  1. 消费者手动确认消费处理

自己情况下,消费者实现了MessageListener,没有手动确认,现在换成ChannelAwareMessageListener,同时消费者<rabbit:listener-container>加上acknowledge="manual",表明手工确认。

【消费者】

public class O implements ChannelAwareMessageListener {

    @Override
    public void onMessage(Message message, Channel channel) throws Exception {
        System.out.println(message);
        channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);// 确认收到消息
    }
}

<rabbit:listener-container connection-factory="connectionFactory" acknowledge="manual">
    <rabbit:listener ref="o" queues="simple-queue"/>
</rabbit:listener-container>

手工确认有3种方式:

 // 注意:打回去的消息又会重新发过来,做好相关的防止死循环处理(可用延时队列)
        /**
         *
         basicAck
         void basicAck(long deliveryTag,
         boolean multiple)
         throws java.io.IOException
         Acknowledge one or several received messages. Supply the deliveryTag from the AMQP.Basic.GetOk or AMQP.Basic.Deliver method containing the received message being acknowledged.
         Parameters:
         deliveryTag - the tag from the received AMQP.Basic.GetOk or AMQP.Basic.Deliver
         multiple - true to acknowledge all messages up to and including the supplied delivery tag; false to acknowledge just the supplied delivery tag.
         Throws:
         java.io.IOException - if an error is encountered
         See Also:
         AMQP.Basic.Ack
         */
        channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);// 确认收到消息

        /*
        basicNack()
        void basicNack(long deliveryTag,
        boolean multiple,
        boolean requeue)
               throws java.io.IOException
        Reject one or several received messages. Supply the deliveryTag from the AMQP.Basic.GetOk or AMQP.Basic.GetOk method containing the message to be rejected.
        Parameters:
        deliveryTag - the tag from the received AMQP.Basic.GetOk or AMQP.Basic.Deliver
        multiple - true to reject all messages up to and including the supplied delivery tag; false to reject just the supplied delivery tag.
                requeue - true if the rejected message(s) should be requeued rather than discarded/dead-lettered
        Throws:
        java.io.IOException - if an error is encountered
        See Also:
        AMQP.Basic.Nack*/
        //channel.basicReject(message.getMessageProperties().getDeliveryTag(), true);// 拒绝消息,为true时,消息被丢弃

        /**
         basicNack()
         void basicNack(long deliveryTag,
         boolean multiple,
         boolean requeue)
         throws java.io.IOException
         Reject one or several received messages. Supply the deliveryTag from the AMQP.Basic.GetOk or AMQP.Basic.GetOk method containing the message to be rejected.
         Parameters:
         deliveryTag - the tag from the received AMQP.Basic.GetOk or AMQP.Basic.Deliver
         multiple - true to reject all messages up to and including the supplied delivery tag; false to reject just the supplied delivery tag.
         requeue - true if the rejected message(s) should be requeued rather than discarded/dead-lettered
         Throws:
         java.io.IOException - if an error is encountered
         See Also:
         AMQP.Basic.Nack
         */
        //channel.basicNack(message.getMessageProperties().getDeliveryTag(), false, true);// 否认消息 打回去

  1. 延时队列(死信)

概:当某个消息处理失败后,打到延时队列,延时队列有过期时间,到了过期时间会把消息转到一个处理异常的队列,重新处理,如果还是失败,就做个记录来人工干预吧。。。

相关知识点:Per-Queue Message TTL、Dead Letter Exchanges

模拟流程:从ofirst队列获取消息,模拟失败,然后入到延时队列,时间过期后,转到olast队列,进行重试或相关操作

【生产者】

P.java

package cn.ywj.dead;

import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class P {

    public static void main(String[] args) {

        ApplicationContext context = new ClassPathXmlApplicationContext("dead/p.xml");
        RabbitTemplate template = context.getBean(RabbitTemplate.class);
        template.convertAndSend("first-queue", "模拟失败信息");
        System.out.println("发送完毕");
    }
}


p.xml

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:rabbit="http://www.springframework.org/schema/rabbit"
       xsi:schemaLocation="http://www.springframework.org/schema/rabbit
           http://www.springframework.org/schema/rabbit/spring-rabbit.xsd
           http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans.xsd">

    <!--工厂类-->
    <rabbit:connection-factory id="connectionFactory" virtual-host="/" host="127.0.0.1" username="guest" password="guest"/>
    <!--消息模样-->
    <rabbit:template id="amqpTemplate" connection-factory="connectionFactory"/>
    <!--管理-->
    <rabbit:admin connection-factory="connectionFactory"/>

    <!-- 1.开始消息从first队列出来-->
    <rabbit:queue name="first-queue"/>
    <!--2.消息处理失败,放到这个延时队列-->
    <rabbit:queue name="dead-letter-queue">
        <rabbit:queue-arguments>
            <entry key="x-message-ttl" value="5000" value-type="java.lang.Long" /> <!--3.时间为5秒-->
            <entry key="x-dead-letter-exchange" value="dead-letter-exchange" /> <!--4.时间过期到转到交换机dead-letter-exchange-->
            <entry key="x-dead-letter-routing-key" value="last-queue" /> <!--key->
        </rabbit:queue-arguments>
    </rabbit:queue>
    <!--重新接收失败消息的队列-->
    <rabbit:queue name="last-queue"/>

    <rabbit:direct-exchange name="dead-letter-exchange">
        <rabbit:bindings>
            <rabbit:binding queue="last-queue" /> <!--5.交换机把失败消息转给last队列-->
        </rabbit:bindings>
    </rabbit:direct-exchange>

</beans>

【消费者】

C.java

package cn.ywj.dead;

import org.springframework.context.support.ClassPathXmlApplicationContext;

public class C {

    public static void main(String[] args) {

        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("dead/c.xml");
        context.start();
    }
}

OFirst.java// 模拟推送到延时队列

package cn.ywj.dead;

import com.rabbitmq.client.Channel;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.amqp.rabbit.listener.api.ChannelAwareMessageListener;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import java.util.Date;

public class OFirst implements ChannelAwareMessageListener {

    @Override
    public void onMessage(Message message, Channel channel) throws Exception {
        System.out.println("[OFirst]:"+ new String(message.getBody())+" "+new Date());
        // 假设错误
        // 推到延时队列去
        ApplicationContext context = new ClassPathXmlApplicationContext("dead/p.xml");
        RabbitTemplate template = context.getBean(RabbitTemplate.class);
        template.convertAndSend("dead-letter-queue", new String(message.getBody()));

        System.out.println(new Date());
        // 假设错误
        channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);// 确认收到消息
    }
}

OLast.java// 接收延时队列里的东西

package cn.ywj.dead;

import com.rabbitmq.client.Channel;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.listener.api.ChannelAwareMessageListener;

import java.util.Date;

public class OLast implements ChannelAwareMessageListener {

    @Override
    public void onMessage(Message message, Channel channel) throws Exception {
        System.out.println("[OLast]:"+ new String(message.getBody())+" "+new Date());
        // 重试或其他记录操作
        // xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
        // 重试或其他记录操作
        channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);// 确认收到消息
    }
}

c.xml

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:rabbit="http://www.springframework.org/schema/rabbit"
       xsi:schemaLocation="http://www.springframework.org/schema/rabbit
           http://www.springframework.org/schema/rabbit/spring-rabbit.xsd
           http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans.xsd">
    <!--工厂类-->
    <rabbit:connection-factory id="connectionFactory" virtual-host="/" host="127.0.0.1" username="guest" password="guest"/>

    <rabbit:admin connection-factory="connectionFactory"/>

    <rabbit:queue name="first-queue"/>
    <rabbit:queue name="last-queue"/>

    <bean id="oFirst" class="cn.ywj.dead.OFirst"/>
    <bean id="oLast" class="cn.ywj.dead.OLast"/>

    <rabbit:listener-container connection-factory="connectionFactory" acknowledge="manual">
        <rabbit:listener ref="oFirst" queues="first-queue" />
        <rabbit:listener ref="oLast" queues="last-queue" />
    </rabbit:listener-container>

</beans>

如果想动态修改延时可以如下修改:

queue-arguments中去掉x-message-ttl

<rabbit:queue name="dead-letter-queue">
    <rabbit:queue-arguments>
        <!--<entry key="x-message-ttl" value="5000" value-type="java.lang.Long" />-->
        <entry key="x-dead-letter-exchange" value="dead-letter-exchange" /> <!--4.时间过期到转到交换机dead-letter-exchange-->
        <entry key="x-dead-letter-routing-key" value="last-queue" />
    </rabbit:queue-arguments>
</rabbit:queue>

Java:

String msg = “123”;

template.convertAndSend("dead-letter-queue",  msg, new MessagePostProcessor(){

    @Override
    public Message postProcessMessage(Message message) throws AmqpException {
        message.getMessageProperties().setExpiration("3000");// 3秒
        message.getMessageProperties().setDeliveryMode(MessageDeliveryMode.PERSISTENT);
        return message;
    }
});

但这样子会有一个问题,当消息A延时8秒,消息B延时3秒,按顺序来添加,3秒后并没有收到B的消息,而是8秒后,A和B的消息同时出来。。。这情况,可以考虑动态添加Queue,实际不会这么做,成本高。。。Demo

Map<String, Object> map = new HashMap<>();
map.put("x-dead-letter-exchange","dead-letter-exchange");
map.put("x-dead-letter-routing-key", "last-queue");

Queue queue = new Queue("A", true, false, true, map);


RabbitAdmin rabbitAdmin = context.getBean(RabbitAdmin.class);
rabbitAdmin.declareQueue(queue);

template.convertAndSend("A", (Object) msg, new MessagePostProcessor(){

    @Override
    public Message postProcessMessage(Message message) throws AmqpException {
        message.getMessageProperties().setExpiration("2000");
        message.getMessageProperties().setDeliveryMode(MessageDeliveryMode.PERSISTENT);
        return message;
    }
});

猜你喜欢

转载自blog.csdn.net/u013845177/article/details/83658576