体能状态先于精神状态,习惯先于决心,聚焦先于喜好
在消息中间件中进行消息的发送和接收是一个非常常见的场景,那么我们的程序在和消息中间件的交互过程中是如何确认处理完毕的呢?比如生产者向消息中间件发送一个消息后,如何告诉消息中间件发送完毕了?又比如从消费者从消息中间件中获取一条消息时,消息中间件是如何确认消费者已经成功处理了消息? 这就涉及到了消息状态确认,即 ACK,下面进行详述
JMS 作为 JAVA 对 消息服务API 的定义,在 javax.jms.Session中定义了四种 ACK 类型
/**生产者或者消费者端设置,自动确认模式,也是默认级别,只要消息被发送完毕,或者接受完毕即算完成*/ static final int AUTO_ACKNOWLEDGE = 1; /**仅在消费者端配置,需要消费者端调用 message.acknowledge() 进行消息确认*/ static final int CLIENT_ACKNOWLEDGE = 2; /**仅在消费端配置,批量消息确认模式,有可能造成消息中间件无法及时收到消息被客户端正确处理的情况,依据消息重试策略可能造成消息重复消费*/ static final int DUPS_OK_ACKNOWLEDGE = 3; /**生产者或者消费者端设置,需要开始事务*/ static final int SESSION_TRANSACTED = 0;ActiveMQ 遵循 JMS 标准,同时也实现了AMQP 等其他协议,除了 JMS 中定义的四种 ACK 类型外,其在 org.apache.activemq.ActiveMQSession还单独定义了一种 ACK 类型
* 翻译:在 INDIVIDUAL_ACKNOWLEDGE 模式下,每次 调用 message.acknowledge() 仅会确认 * 一条消息,作为对比,在 CLIENT_ACKNOWLEDGE 模式下,在一个 session 中可以一次消费多个消息 * ,但是仅调用一次 acknowledge() 即可表示对所有消息的确认 * * Only acknowledge an individual message - using message.acknowledge() * as opposed to CLIENT_ACKNOWLEDGE which * acknowledges all messages consumed by a session at when acknowledge() * is called */ public static final int INDIVIDUAL_ACKNOWLEDGE = 4;在上面对讨论中我们可以看到客户端消费消息后可以通过调用 message.acknowledge() 来进行消息确认,但是在 JmsTemplate 提供对方法中,即使你进行了这样对配置,客户端也无法去调用 message.acknowledge() ,消息看起来每次都被默认提交了,why?
JmsTemplate 作为Spring 对 消息服务提供的模版,其存在的意义就是为了免去绝大多数可以省去的配置,所以默认来说 JmsTemplate 会自动提交事务,即 AUTO_ACKNOWLEDGE 模式 你可以联想JDBC 是不是也是这么回事,在使用Mybatis时事务也是默认提交的,除非你同时使用事务配置.对于JmsTemplate 而言,如果你想加入事务配置,也需要添加单独的配置
所以,如果你想手动确认消息,那么还是乖乖使用 ActiveMQ 提供的方法,如果你使用了 JmsTemplate 那么要么接受默认消息确认机制,要么新增一个事务配置,这样至少你可以进行消息的回滚,关于这些实现将在下面进行呈现.