Announcement Announcement Module
Collapse
No announcement yet.
Sharing a JMS session between producer and consumer from different topics using Sprin Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Sharing a JMS session between producer and consumer from different topics using Sprin

    How can I share a single session between two topics using Spring?

    Without Spring it is straightforward to do
    Look up ConnectionFactory using either of the two clientIds (both topics are on same broker)
    Code:
        Connection connection = connectionFactory.createConnection();
        session = connection.createSession(true, Session.AUTO_ACKNOWLEDGE);
        session.createdurableSubscriber(Topic A);
        session.createProducer(Topic B);
    so this way both the consumer for topic A and producer for topic B come under the same session.
    I want to replicate this behavior using the Spring framework

    What I have so far is two jmsTemplates

    Code:
        <bean id="jmsTemplate" class="org.springframework.jms.core.JmsTemplate">
        <property name="connectionFactory" ref="connectionFactory1"/>
        <property name="pubSubDomain" value="true"/>
        <property name="deliveryPersistent" value="true"/>
        </bean>
    	
        <bean id="jmsTemplate1" class="org.springframework.jms.core.JmsTemplate">
        <property name="connectionFactory" ref="connectionFactory2"/>
        <property name="pubSubDomain" value="true"/>
        <property name="deliveryPersistent" value="true"/>
        </bean>
    ConnectionFactory1 and ConnectionFactory are different in that the name used to look them up in the JNDI is different as they both have different client IDs.

  • #2
    One option is to use the JmsTemplate's execute method which requires a SessionCallback. In that callback you are handed the Session being used and can perform any low-level operations you need directly with the JMS API.

    I'm a bit confused that you talk about needing the same Session but then show 2 different ConnectionFactories in use, but maybe you are just showing that you have more than one JmsTemplate within the application?

    Hope that helps.
    -Mark

    Comment


    • #3
      Is there any way in the xml to indicate that I want the same sesion to be used?
      What if I use the same jmsTemplate for both the producer and consumer (and specify a different clientId for the MessageListener)

      Code:
                    <bean id="jmsTemplate" class="org.springframework.jms.core.JmsTemplate">
                          <property name="connectionFactory" ref="connectionFactory"/>
                         <property name="pubSubDomain" value="true"/>
                         <property name="deliveryPersistent" value="true"/>
                    </bean>
      
               <bean id="stagingMessageListener" class="org.springframework.jms.listener.DefaultMessageListenerContainer">
      		<property name="connectionFactory" ref="connectionFactory"/>
      		<property name="destination" ref="topicA"/>
      		<property name="messageListener" ref="messageListener"/>
      		<property name="sessionAcknowledgeModeName" value="AUTO_ACKNOWLEDGE"/>
      		<property name="subscriptionDurable" value="true"/>
      		<property name="clientId" value="XYZ"/>
      	</bean>
      	
      	<bean id="notificationSender" class="abc.my.MessageSender">
      		<constructor-arg index="0" type = "javax.jms.Destination" ref="topicB"/>
      		<constructor-arg index="1" type = "org.springframework.jms.core.JmsTemplate" ref="jmsTemplate"/>
      	</bean>
      Since they now share the same connectionFactory is there any way for them to share the same session.
      I am trying to make the receive() and publish() execute under the same session so that I can perform an atomic commit or rollback

      Comment


      • #4
        If you set sessionAcknowledgeMode="transacted", any jmsTemplate operations on the same thread will use the same session (do not add a transactionManager; it will just use a local transaction on the session).

        Comment


        • #5
          Sorry; since you are not using namespace support, you need to set sessionTransacted to "true".

          With the <jms:message-listener-container/> namespace, transactions are enabled via acknowledge-mode="transacted".

          Comment


          • #6
            Thanks Gary,
            So if I set sessionTransacted= true; I don't need to do this,

            Code:
            jmsTemplate.execute(new SessionCallback<Object>() {
            
            				public Object doInJms(Session session) throws JMSException {
            					session.commit();
            					return null;
            				}
            			});
            Is that correct?
            Is the commit() taken care of for me, if so then when does it happen?
            Also for certain Exceptions (InvalidMessageException), I want the MessageListener to commit() and not rollback(). Is the default behavior for exceptions in the MessageListener rollback() or commit()?

            Comment


            • #7
              Yes, with transacted sessions, the listener container takes care of the commit for you, when the message listener returns. The session is bound to the thread - that's how the jmstemplate gets access to it.

              Exceptions will cause a rollback; simply catch any exceptions in the listener for which you want the receive() to commit.

              Comment


              • #8
                Awesome thanks,

                Also if a the connection to the broker is lost during the onMessage() does the JMSTemplate handle the rollback and reconnect for me?
                Where can I read more about how the reconnect is handled?

                Comment


                • #9
                  No; if the connection is lost, the session will be bad and the template will throw a (JMS) exception; let this propagate back to the listener container and he will take care of reconnecting. Since the connection was lost during a transaction everything will be rolled back.

                  I suggest you read the chapter on JMS in the Spring Reference...

                  http://static.springsource.org/sprin.../html/jms.html

                  Comment


                  • #10
                    Thanks Gary,

                    On the link you mentioned when they talk about Synchronous Receive they say:

                    While JMS is typically associated with asynchronous processing, it is possible to consume messages synchronously. The overloaded receive(..) methods provide this functionality. During a synchronous receive, the calling thread blocks until a message becomes available.
                    What overloaded receive method are they talking about? The only receive I can see on the JMSTemplate is receive(Destination)
                    Last edited by [email protected]; May 9th, 2012, 04:08 PM.

                    Comment


                    • #11
                      I got the answer to that one. jmsTemplate.receive() methods are synchronous. I have run into another problem of how to use synchronous receive using jmstemplate when I need a durable subscriber. Thats a different thread though:
                      http://forum.springsource.org/showth...ableSubscriber

                      Comment

                      Working...
                      X