Search code examples
spring-mvcjbossjmsspring-jmsjmstemplate

How to implement JMS local queue using Spring 3.05 and JBoss 5.1 (JBossMQ)?


There is an application based on Spring 3.0.5 framework running on JBoss 5.1 server.

I tried to follow this tutorial, but it uses the ActiveMQ broker instead of JBossMQ (default JBoss 5.1 broker).

I've already set a queue called MyQueue in JBoss config (destinations-service.xml):

<mbean code="org.jboss.jms.server.destination.QueueService"
  name="jboss.messaging.destination:service=Queue,name=MyQueue"
  xmbean-dd="xmdesc/Queue-xmbean.xml">
  <depends optional-attribute-name="ServerPeer">jboss.messaging:service=ServerPeer</depends>
  <depends>jboss.messaging:service=PostOffice</depends>

You can see the rest of my config below. What am I missing? How can I specify the JNDI name of the queue and the connection factory? And what about the server address ([ConnectionFactory] Connector bisocket://localhost:4457)?

My config in applicationContext.xml is as follow:

<bean id="connectionFactory" class="org.jboss.jms.server.connectionfactory.ConnectionFactory" />

<bean id="messageDestination" class="javax.jms.Queue" />

<bean id="jmsTemplate" class="org.springframework.jms.core.JmsTemplate">
    <property name="connectionFactory" ref="connectionFactory" />
    <property name="receiveTimeout" value="10000" />
</bean>

<bean id="springJmsProducer" class="myPackage.QueueProducer">
    <property name="destination" ref="messageDestination" />
    <property name="jmsTemplate" ref="jmsTemplate" />
</bean> 

<bean id="messageListener" class="myPackage.QueueConsumer" />

My Producer:


 public class QueueProducer {

    private JmsTemplate jmsTemplate;

    private Queue queue;

    public void setConnectionFactory(ConnectionFactory cf) {
        this.jmsTemplate = new JmsTemplate(cf);
    }

    public void setQueue(Queue queue) {     
        this.queue = queue;
    }

    public void send(Object object) {
        this.jmsTemplate.send(this.queue, new MessageCreator() {
            public Message createMessage(Session session) throws JMSException {
              return session.createTextMessage("my text to send");
            }
        });
    }
}

My Consumer:




public class QueueConsumer implements MessageListener {

    @Override
    public void onMessage(Message message) {
        if (message instanceof TextMessage) {
            try {
                System.out.println(((TextMessage) message).getText());
            }catch (JMSException ex) {
                throw new RuntimeException(ex);
            }
        }
        else {
            throw new IllegalArgumentException("Message must be of type TextMessage");
        }

    }
}

Solution

  • What you want is most likely jndiTemplate. Also, you're not quite wiring the jmsTemplate beans together correctly. Here's a piece by piece explanation of what you need in your Spring applicationContext.

    You'll need to setup a jndiTemplate to inject the JBoss JNDI implementation:

    <bean id="jndiTemplate" class="org.springframework.jndi.JndiTemplate">
        <property name="environment">
            <props>
                <prop key="java.naming.factory.initial">
                    org.jnp.interfaces.NamingContextFactory
                </prop>
                <prop key="java.naming.provider.url">
                    jnp://localhost:1099
                </prop>
                <prop key="java.naming.factory.url.pkgs">
                    org.jboss.naming:org.jnp.interfaces
                </prop>
            </props>
        </property>
    </bean>
    

    Then, configure the ConnectionFactory to point at the above JNDI config:

    <!-- spring JMS definition -->
    <bean name="jmsConnectionFactory" class="org.springframework.jndi.JndiObjectFactoryBean">
        <property name="jndiTemplate" ref="jndiTemplate"/>
        <property name="jndiName" value="ConnectionFactory" />
    </bean>
    

    Configure the transaction manager with the above ConnectionFactory:

    <bean id="jmsTransactionManager" class="org.springframework.jms.connection.JmsTransactionManager">
        <property name="connectionFactory" ref="jmsConnectionFactory" />
    </bean>
    

    Associate the destination with the jndiTemplate and jndiName:

    <!-- jms destination already defined in jboss -->
    <bean name="myQueue" class="org.springframework.jndi.JndiObjectFactoryBean">
        <property name="jndiTemplate" ref="jndiTemplate"/>
        <property name="jndiName" value="queue/MyQueue" />
    </bean>
    

    Finally, configure the jmsTemplate itself to point at the ConnectionFactory, and you're ready to use JmsTemplate in your code:

    <bean id="jmsTemplate" class="org.springframework.jms.core.JmsTemplate">
        <property name="connectionFactory" ref="connectionFactory" />
    </bean>
    

    You'll also want a message listener container configuration to run your consumer. Replace "jmsexample.ExampleListener" with the name of the class that contains your MessageListener:

    <!-- this is the Message Driven POJO (MDP) -->
    <bean id="messageListener" class="jmsexample.ExampleListener" />
    
    <!-- and this is the message listener container -->
    <bean id="jmsContainer" class="org.springframework.jms.listener.DefaultMessageListenerContainer">
        <property name="connectionFactory" ref="connectionFactory"/>
        <property name="destination" ref="myQueue"/>
        <property name="messageListener" ref="messageListener" />
    </bean>