2

I know this sounds as heard 1000 times, but I don't think so and I could not really find a solution:

With common ejb I can use acknowledge mode to acknowledge() message manually. If I don't do it is redelivered. I did this in the past and it worked well.

Using Spring JMS I have the problem that it seems I either can set redelivery to be processed only if an exception is thrown or not at all.

How to realize it as with ejb?

My problem is: If the message is acknowledged I DON'T want it to be redelivered at all, even if an exception occurs.

user5101998
  • 209
  • 3
  • 9

3 Answers3

1

We can use spring framework's DefaultMessageListenerContainer for your requirement.

Please find below documentation from Spring:

In a fashion similar to a Message-Driven Bean (MDB) in the EJB world, the Message-Driven POJO (MDP) acts as a receiver for JMS messages. The one restriction (but see also below for the discussion of the MessageListenerAdapter class) on an MDP is that it must implement the javax.jms.MessageListener interface. Please also be aware that in the case where your POJO will be receiving messages on multiple threads, it is important to ensure that your implementation is thread-safe.

http://docs.spring.io/spring/docs/2.5.x/reference/jms.html#jms-asynchronousMessageReception

The following is the code snippet in which I have added acknowledge() method on the method.

JMS Listener Class:

public class MyProjectJMSListener implements MessageListener {
    public void onMessage(Message message) {
        try {
            message.acknowledge();
            //Business logic to be added 
        }
        catch (JMSException ex) {
                throw new RuntimeException(ex);
        }       
    }
}

spring-jms-config.xml

<bean id="messageListener" class="com.myproj.MyProjectJMSListener" />

<bean id="jmsContainer" class="org.springframework.jms.listener.DefaultMessageListenerContainer">
    <property name="connectionFactory" ref="connectionFactory"/>  <!-- connectionFactory bean class to be added -->
    <property name="destination" ref="my.jms.destination"/> 
    <property name="messageListener" ref="messageListener" />
</bean>
Vasu
  • 21,832
  • 11
  • 51
  • 67
1

thanks for the response. But, I did it exactly like this, except that I use Spring 3 and annotation config. The problem is not the receiving but the acknowledgement. If I use a transaction or not, it seems the message is acknowledged automatically while receiving.

I tried it extending MessageListener directly and folowing way .. noting works.

public class JMSListener implements SessionAwareMessageListener<TextMessage> {
...

    @Override
    public void onMessage(TextMessage message, Session session) {
        ...
    }
}

This way I'm able to see the session settings. E.g. session.getAcknowledgeMode() delivers client acknowledge and session.getTransacted() delivers true or false depending on what I set. But it seems there is no effect. The message seems to be acknowledged anyway.

There is also a difference in java doc for CLIENT_ACKNOWLEDGE of spring and jee. For spring there is written:

"CLIENT_ACKNOWLEDGE": Automatic message acknowledgment after successful listener execution; no redelivery in case of exception thrown.

For jee there is written:

CLIENT_ACKNOWLEDGE With this acknowledgment mode, the client acknowledges a consumed message by calling the message's acknowledge method.

For me this could be the reason? But if this is really the case (and I could'nt believe it) it would make spring unusable handling messages?

user5101998
  • 209
  • 3
  • 9
0

"sessionAcknowledgeMode" set to "AUTO_ACKNOWLEDGE" (default): This mode is container-dependent: For DefaultMessageListenerContainer, it means automatic message acknowledgment before listener execution, with no redelivery in case of an exception and no redelivery in case of other listener execution interruptions either. For SimpleMessageListenerContainer, it means automatic message acknowledgment after listener execution, with no redelivery in case of a user exception thrown but potential redelivery in case of the JVM dying during listener execution. In order to consistently arrange for redelivery with any container variant, consider "CLIENT_ACKNOWLEDGE" mode or - preferably - setting "sessionTransacted" to "true" instead. "sessionAcknowledgeMode" set to "DUPS_OK_ACKNOWLEDGE": Lazy message acknowledgment during (DefaultMessageListenerContainer) or shortly after (SimpleMessageListenerContainer) listener execution; no redelivery in case of a user exception thrown but potential redelivery in case of the JVM dying during listener execution. In order to consistently arrange for redelivery with any container variant, consider "CLIENT_ACKNOWLEDGE" mode or - preferably - setting "sessionTransacted" to "true" instead. "sessionAcknowledgeMode" set to "CLIENT_ACKNOWLEDGE": Automatic message acknowledgment after successful listener execution; best-effort redelivery in case of a user exception thrown as well as in case of other listener execution interruptions (such as the JVM dying). "sessionTransacted" set to "true": Transactional acknowledgment after successful listener execution; guaranteed redelivery in case of a user exception thrown as well as in case of other listener execution interruptions (such as the JVM dying).

Spring JMS framework expose an upper level of abstraction for acknowledgement for messages. Users only need to concern the scenario of whether to redeliver the message if user exception happens.

So, cares should be taken for the bean of message listener container factory and configure the jms option correspondly.

GaryLiu
  • 1
  • 1