Получение простого клиента Spring JMS для работы

Только начинаю опускать голову JMS ActiveMQ Acknowledgements, работая в Spring. Пока у меня есть потребитель, который отлично работает, за исключением того, что, когда я не подтверждаю сообщение, он все еще берется из очереди (я ожидаю, что он останется там или закончится в очереди с мертвой буквой).

      

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

    <!-- A JMS connection factory for ActiveMQ -->
    <bean id="connectionFactory" class="org.apache.activemq.ActiveMQConnectionFactory"
    p:brokerURL="failover://(tcp://jms1:61616,tcp://jms2:61616)?randomize=false&amp;jms.redeliveryPolicy.maximumRedeliveries=5" />

    <!-- A POJO that implements the JMS message listener -->
    <bean id="simpleMessageListener" class="com.company.ConsumerClass" />

    <!-- A JMS namespace aware Spring configuration for the message listener container -->
    <jms:listener-container
            container-type="default"
            connection-factory="connectionFactory"
            acknowledge="client"
            concurrency="10-50"
            cache="consumer">
        <jms:listener destination="someQueue" ref="simpleMessageListener" method="onMessage" />
    </jms:listener-container>
</beans>

В ConsumerClass мой простой потребитель выглядит примерно так:

@Override public final void onMessage(Message message) {
    Object postedMessage = null;
    try {
        postedMessage = ((ObjectMessage) message).getObject();

        if (postedMessage.getClass() == SomeMessageType.class) {
            try {
                //Some logic here

                message.acknowledge();
                return; //Success Here
            } catch (MyException e) {
                logger.error("Could not process message, but as I didn't call acknowledge I expect it to end up in the dead message queue");
            }
        }
    } catch (JMSException e) {
        logger.error("Error occurred pulling Message from Queue", e);
    }

    //Also worth noting, if I throw new RuntimeException("Aww Noos"); here then it won't take it from the queue, but it won't get consumed (or end up as dead letter)...
}

Ответ 1

Я нашел ответ на http://ourcraft.wordpress.com/2008/07/21/simple-jms-transaction-rollbacks-work/

Кажется, что он работает хорошо, если вы меняете accept = "transacted" и убедитесь, что вы выбрали новое RuntimeException ( "Сообщение не может быть использовано. Откат транзакции" ); в конце процедуры OnMessage().

По-прежнему не знаю, что признает = "клиент", хотя

Ответ 2

Прочтите эту документацию: Spring Контейнер JMS не использует message.acknowledge()

Консоль слушателя предлагает следующие варианты подтверждения сообщения:

"sessionAcknowledgeMode" установлен на "AUTO_ACKNOWLEDGE" (по умолчанию): автоматическое подтверждение сообщения перед исполнением слушателя; нет redelivery в случае исключения брошенных.
"sessionAcknowledgeMode" установлен на "CLIENT_ACKNOWLEDGE": автоматическое подтверждение сообщения после успешного выполнения прослушивателя; нет redelivery в случае исключения брошенных.
"sessionAcknowledgeMode" установлен на "DUPS_OK_ACKNOWLEDGE": ленивое подтверждение сообщения во время или после исполнения слушателя; потенциальная переадресация в случае возникновения исключения.
"sessionTransacted" установлен на "true": подтверждение транзакции после успешного выполнения прослушивателя; гарантированная доставка в случае исключения.

Ответ 3

В настоящее время Spring обеспечивает хорошую обертку поверх обычных прослушивателей сообщений JMS.

См. JavaDocs AbstractMessageListenerContainer.

"sessionAcknowledgeMode" установлен на "CLIENT_ACKNOWLEDGE": автоматическое подтверждение сообщения после успешного выполнения прослушивателя; переустановку с наилучшим усилием при возникновении исключения пользователя, а также в случае прерываний выполнения другого слушателя (например, JVM умирает).

Итак, когда вы определяете метод @JmsListener, подтверждение отправляется автоматически, когда оно завершено успешно, но вы можете сделать исключение для снова получите сообщение.

Ответ 4

Используйте следующий код, который будет работать.

<bean id="{containerName}"  class="org.springframework.jms.listener.DefaultMessageListenerContainer">
    <property name="connectionFactory" ref={connectionFactoryBean} />
    <property name="destinationName" ref="{queue}" />
    <property name="messageListener" ref="{listner}" />
    <property name="sessionAcknowledgeModeName" value="CLIENT_ACKNOWLEDGE"/>
</bean>

Ответ 5

Метод подтверждения вызова() в сообщении вашего потребителя.

Рассмотрим следующий сценарий: приложение получает, но не подтверждает сообщение. Приложение получает последующее сообщение и подтверждает его. Что происходит с прежним сообщением? Первое сообщение также считается признанным. Как правило, подтверждение конкретного сообщения подтверждает все предыдущие сообщения, полученные сеансом. В приведенном выше выводе явно подтверждается только сообщение 5. Все сообщения до сообщения 5 неявно подтверждены. Сообщения после сообщения 5 не подтверждаются.

Подробнее см. в этой статье

Также проверьте эту статью Sun Java System Message Queue 4.3 Руководство разработчика для клиентов Java

Ответ 6

В моей практике признание клиента редко, если оно когда-либо используется. Типичная настройка автоматически подтверждается, поэтому, если ваш код возвращается из onMessage() обычно (без исключения), сообщение автоматически подтверждается. Если ваш код выдает исключение из onMessage(), подтверждения нет, и сообщение обычно будет повторно отправлено до предварительно настроенного количества раз, после чего оно обычно будет отброшено или помещено в очередь мертвых сообщений.

В вашем случае, с точки зрения сервера JMS, похоже, что клиент запрашивал сообщение, но никогда не подтверждал его, так что он все еще "обрабатывается" клиентом. В таком случае сообщение будет невидимым для других пользователей в той же очереди, чтобы вы могли создать впечатление, что сообщение "снимает очередь", в то время как по сути оно все еще существует. Очевидно, вы не увидите такое сообщение в очереди сообщений.

Я предлагаю вам прочитать спецификацию JMS, чтобы получить четкое представление о различных режимах подтверждения.