SpringBoot整合activeMQ消息队列手动签收(Session.CLIENT_ACKNOWLEDGE)为什么失效啊?

     今天在家隔离办公,不太忙,然后就琢磨起来消息队列activeMQ的消息事务来解决分布式事务,但是奈何在SpringBoot整合activeMQ时,其消费者手动签收消息时出现了问题——>当activeMQ设置为手动签收(Session.CLIENT_ACKNOWLEDGE)时,我明明在消费消息时没有执行mapMessage.acknowledge()方法,但是却将消息消费成功了,可郁闷了,哪也就是这个手动签收完全没有生效,郁闷死了,搞了两个小时完全没搞懂,然后网上也找不到类似的踩坑记录,后来给解决了这个坑,那么为了让咱们不再踩坑,这里我来给大家解决下,废话少说,老规矩,来扔干货。
     大家能搜到我这篇文章,想必大家肯定已经对activeMQ已经有了大部分了解了,我就不给大家从头一点一点的讲解其知识了,直接说这个解决问题。
     为了节省大家时间,大家可以看这段代码直接解决问题,如果能解决就不用看下面的废话,下面一堆废话,实际有用的也就这一点——> 就是在config配置类中设置factory.setSessionAcknowledgeMode(Session.AUTO_ACKNOWLEDGE);更改为factory.setSessionAcknowledgeMode(4);即可解决手动签收失败问题。

          上面哪一段大家如果没有看懂也没关系,那么请接着往下读详细内容

     在SpringBoot整合activeMQ之前,我创建了最基本的那种生产者和消费者,在这种消费者类中我设置的其消息签收模式为手动签收,这种我测试的是成功的,也就是只有在执行ackno wledge()方法之后,其消息才是真正签收成功,否则消息签收失败,消息仍然在消息队列中,其它消费者仍然可以在该消息队列中拿到其消息进行消费。代码如下:

public static void main(String[] args) {

        ActiveMQConnectionFactory activeMQConnectionFactory = new ActiveMQConnectionFactory("tcp://127.0.0.1:61616");
        Connection connection = null;
        try {
            connection = activeMQConnectionFactory.createConnection();
            connection.start();
            /**
             * 第一个参数:是否开启事务;第二个参数:签收的几种方式
             * 自动签收(Session.AUTO_ACKNOWLEDGE):该方式是默认的。该种方式,无需我们程序做任何操作,框架会帮我们自动签收收到的消息。
             * 手动签收(Session.CLIENT_ACKNOWLEDGE):手动签收。该种方式,需要我们手动调用Message.acknowledge(),来签收消息。如果不签收消息。该消息会被我们反复消费,直到被签收
             * 允许重复消息(Session.DUPS_OK_ACKNOWLEDGE):多线程或多个 消费者同时消费到一个消息,因为先成功不安全,可能会重复消费。该种方式很少使用到。
             * 事务下的签收(SESSION.SESSION_TRANSACTED):开始事务的情况下,可以使用该方式。该种方式很少使用到。
             */
            //Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
            //Session session = connection.createSession(true, Session.SESSION_TRANSACTED);
            Session session = connection.createSession(false, Session.CLIENT_ACKNOWLEDGE);
            Queue queue = session.createQueue("test01");
            MessageConsumer consumer = session.createConsumer(queue);
            consumer.setMessageListener(new MessageListener() {
                @Override
                public void onMessage(Message message) {

                    if (message instanceof TextMessage) {
                        String text = null;

                        try {
                            text = ((TextMessage) message).getText();
                            System.out.println(text);
                            message.acknowledge();
                        } catch (JMSException e) {
                            e.printStackTrace();
                        }
                    }
                }
            });
        } catch (JMSException e) {
            e.printStackTrace();
        }
    }

     上面这个消费者就是让大家看下其知识点,注意点在以下两个地方:
在这里插入图片描述在这里插入图片描述     上面中给大家展示这么多,就是为了告诉大家如果想要消费者手动签收消费,那么首先要将session设置为手动签收模式(Session.CLIENT_ACKNOWLEDGE),然后在消费消息之后,执行acknowledge()方法,则该消息会签收成功。
     在上面这种方式中已经手动签收成功,但是难就难在了在整合SpringBoot的时候却失败了,失败了,郁闷,下面说解决方案:

解决方案:

     下面我依次给大家activeMQ的配置类、activeMQ工具类和消费端代码,如下所示:
配置类config如下所示:

/**
 * ActiveMQ 配置类
 * @ClassName: ActiveMQConfig
 * @Author: ygl
 * @Date: 2022/3/30 16:14
 * @Version: 1.0
 */
@Configuration
public class ActiveMQConfig {

    @Value("${spring.activemq.broker-url:disabled}")
    String brokerURL;

    @Value("${activemq.listener.enable:disabled}")
    String listenerEnable;

    @Bean
    public ActiveMQUtil getActiveMQUtil() throws JMSException {

        if (brokerURL.equals("disabled")) {
            return null;
        }
        ActiveMQUtil activeMQUtil = new ActiveMQUtil();
        activeMQUtil.init(brokerURL);
        return activeMQUtil;
    }

    //定义一个消息监听器连接工厂,这里定义的是点对点模式的监听器连接工厂
    @Bean(name = "jmsQueueListener")
    public DefaultJmsListenerContainerFactory jmsQueueListenerContainerFactory(
            ActiveMQConnectionFactory activeMQConnectionFactory) {

        DefaultJmsListenerContainerFactory factory = new DefaultJmsListenerContainerFactory();
        if (!listenerEnable.equals("true")) {
            return null;
        }

        factory.setConnectionFactory(activeMQConnectionFactory);
        //设置并发数
        factory.setConcurrency("5");

        //重连间隔时间
        factory.setRecoveryInterval(5000L);
        //设置为点对点(p2p)模式
        factory.setPubSubDomain(false);
        //作为生产者如果需要支持事务,则需要配置SessionTransacted为true
        factory.setSessionTransacted(false);
        //消息的应答方式,需要手动确认,此时SessionTransacted必须被设置为false,且为Session.CLIENT_ACKNOWLEDGE模式
        //Session.AUTO_ACKNOWLEDGE  消息自动签收
        //Session.CLIENT_ACKNOWLEDGE  客户端调用acknowledge方法手动签收  注意在SpringBoot里面手动确认是失效的,要设置为 4
        //Session.DUPS_OK_ACKNOWLEDGE 不必必须签收,消息可能会重复发送
        //factory.setSessionAcknowledgeMode(4);
        factory.setSessionAcknowledgeMode(Session.CLIENT_ACKNOWLEDGE);
        return factory;
    }

    @Bean(name = "topicListenerContainerFactory")
    public JmsListenerContainerFactory topicListenerContainerFactory(ConnectionFactory connectionFactory) {

        DefaultJmsListenerContainerFactory factory = new DefaultJmsListenerContainerFactory();
        if (!listenerEnable.equals("true")) {
            return null;
        }
        factory.setConnectionFactory(connectionFactory);
        factory.setPubSubDomain(true);
        return factory;
    }


    @Bean
    public ActiveMQConnectionFactory activeMQConnectionFactory() {
        /*if((url==null||url.equals(""))&&!brokerURL.equals("disabled")){
            url=brokerURL;
        }*/
        ActiveMQConnectionFactory activeMQConnectionFactory =
                new ActiveMQConnectionFactory(brokerURL);
        return activeMQConnectionFactory;
    }
}

spring.activemq.broker-url和activemq.listener.enable在yml配置中如下图所示:
在这里插入图片描述
activeMQUtil工具类如下所示:

public class ActiveMQUtil {

    PooledConnectionFactory pooledConnectionFactory = null;

    public ConnectionFactory init(String brokerUrl) {

        ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory(brokerUrl);
        //加入连接池
        pooledConnectionFactory = new PooledConnectionFactory(factory);
        //出现异常时重新连接
        pooledConnectionFactory.setReconnectOnException(true);
        //
        pooledConnectionFactory.setMaxConnections(5);
        pooledConnectionFactory.setExpiryTimeout(10000);
        return pooledConnectionFactory;
    }

    public ConnectionFactory getConnectionFactory() {
        return pooledConnectionFactory;
    }
}

消费端代码如下所示:

/**
 * 消息队列 监听
 * @ClassName: MQListener
 * @Author: ygl
 * @Date: 2022/3/30 21:44
 * @Version: 1.0
 *
 */
@Component
public class MQListener {

@JmsListener(destination = "payment_testMQ_producer", containerFactory = "jmsQueueListener")
public void testMQConsumerThree(MapMessage mapMessage, Session session) {

        String name = null;
        String age = null;
        try {
            name = mapMessage.getString("name");
            age = mapMessage.getString("age");
            TestActiveMQDTO testActiveMQDTO = new TestActiveMQDTO();
            testActiveMQDTO.setName(name);
            testActiveMQDTO.setAge(Integer.parseInt(age));
            System.out.println("我是Three——>姓名:" + name + ";年龄:" + age);
            //session.rollback();
            mapMessage.acknowledge();
        } catch (JMSException e) {
            e.printStackTrace();
        }
    }
}

好,上面就是我的所有代码,其实只有三个点比较重要,我来给大家在下面的图片中标注出来:
在这里插入图片描述在这里插入图片描述
     上面这两张照片截图中已经详细的介绍了activeMQ的config配置和消费者监听的类,看着上面完全没问题,对,你看的是不是也没问题,但是我在消费时不执行mapMessage.acknowledge();方法去手动签收,但是该消息队列仍然签收成功,可郁闷可郁闷,为什么会呢?
     后面网上找了资源,看下些源码发现源码中有这样一段代码:
在这里插入图片描述在这里插入图片描述

     上面图中的源码很清楚的介绍了为什么自动执行,我也在图中标注的比较清楚,这里我也不过多解释,请仔细看上面图中源码。
解决方案:
     就是在config配置类中设置 factory.setSessionAcknowledgeMode(Session.AUTO_ACKNOWLEDGE);更改为factory.setSessionAcknowledgeMode(4); 即可解决手动签收失败问题。
在这里插入图片描述     好了,这就是我今天activeMQ消息手动签收遇到的问题,哪里有需要改正的和大家不懂的请帮忙给我指出,我将改正或者在评论里给大家再讲解下。
     大家如果想详细的了解activeMQ,请移步至这篇文章——>activeMQ基础学习和SpringBoot整合activeMQ案例;这篇文章中有详细介绍。
     大家记得点赞收藏加评论哦,明天上午继续加油,争取出来activeMQ的详细讲解。明天见,拜拜。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

岭岭颖颖

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值