Реализация обмена сообщениями JMS - PullRequest
5 голосов
/ 22 марта 2010

Я боролся с этой «простой» задачей для более опытных людей, я застрял на 2 дня, теперь нуждаюсь в помощи. Я изменил вещи, как миллионы раз, наконец, я наткнулся на этой весной учебник JMS .

Что я хочу сделать, отправить сообщение и получить его. Я также читал эту книгу главу 8 об обмене сообщениями. Это действительно хорошо объясняет 2 типа сообщений, и есть хороший пример для publish-and-subscribe типа, но теперь пример для point-to-point сообщений ( это тот, который мне нужен ).

Я могу самостоятельно отправить сообщение в очередь, но не имею понятия, как его получить, вот почему я попробовал это весеннее руководство, вот что я получил до сих пор:

ПЕРЕСМОТРЕННЫЙ ОТПРАВИТЕЛЬ:

package quartz.spring.com.example; 

import java.util.HashMap; 
import java.util.Map; 

import javax.jms.ConnectionFactory; 
import javax.jms.Destination; 
import javax.jms.JMSException; 
import javax.jms.Message; 
import javax.jms.Queue; 
import javax.jms.Session; 

import org.springframework.jms.core.MessageCreator; 
import org.springframework.jms.core.JmsTemplate; 
import org.springframework.jms.core.JmsTemplate102; 
import org.springframework.jms.core.MessagePostProcessor; 

public class JmsQueueSender { 

    private JmsTemplate jmsTemplate; 
    private Destination destination; 

    public void setConnectionFactory(ConnectionFactory cf) { 
        this.jmsTemplate = new JmsTemplate102(cf, false); 
    } 

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

    public void simpleSend() { 
        this.jmsTemplate.send(this.destination, new MessageCreator() { 
            public Message createMessage(Session session) throws JMSException { 
              return session.createTextMessage("hello queue world"); 
            } 
        }); 
    } 

    public void sendWithConversion() { 
        Map map = new HashMap(); 
        map.put("Name", "Mark"); 
        map.put("Age", new Integer(47)); 
        jmsTemplate.convertAndSend("ReceiverQueue", map, new MessagePostProcessor() { 
            public Message postProcessMessage(Message message) throws JMSException { 
                message.setIntProperty("AccountID", 1234); 
                message.setJMSCorrelationID("123-00001"); 
                return message; 
            } 
        }); 
    } 
} 

ПРИЕМНИК:

package quartz.spring.com.example;

import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageListener;
import javax.jms.TextMessage;

public class ExampleListener implements MessageListener {

    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");
        }
    }
}

отредактировано applicationcontext.xml

      <?xml version="1.0" encoding="UTF-8"?> 
<beans xmlns="http://www.springframework.org/schema/beans" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:jee="http://www.springframework.org/schema/jee" 
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd 
        http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-2.0.xsd"> 

    <bean id="sender" class="quartz.spring.com.example.JmsQueueSender" 
        init-method="sendWithConversion" /> 
    <bean id="receiver" class="quartz.spring.com.example.ExampleListener"> 
    </bean>  

    <bean id="jmsContainer" 
        class="org.springframework.jms.listener.DefaultMessageListenerContainer"> 
        <property name="connectionFactory" ref="connectionFactory" /> 
        <property name="destination" ref="queueDestination" /> 
        <property name="messageListener" ref="messageListener" /> 
    </bean> 

    <!-- Queue configuration --> 
    <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> 
                <prop key="java.naming.security.principal">admin</prop> 
                <prop key="java.naming.security.credentials">admin</prop> 
            </props> 
        </property> 
    </bean> 

    <bean id="connectionFactory" class="org.springframework.jndi.JndiObjectFactoryBean"> 
        <property name="jndiTemplate" ref="jndiTemplate" /> 
        <property name="jndiName" value="ConnectionFactory" /> 
    </bean> 

    <bean id="queueDestination" class="org.springframework.jndi.JndiObjectFactoryBean"> 
        <property name="jndiTemplate" ref="jndiTemplate" /> 
        <property name="jndiName"> 
            <value>queue/ReceiverQueue</value> 
        </property> 
    </bean> 
</beans> 

На самом деле не знал, что кривая обучения для этого так долго, я имею в виду идею очень проста:

  1. Отправить сообщение в очередь назначения
  2. Получение сообщения из очереди назначения

Чтобы получать сообщения, вы делаете следующее (так говорит книга):

1 Locate a ConnectionFactory, typically using JNDI.
2 Use the ConnectionFactory to create a Connection.
3 Use the Connection to create a Session.
4 Locate a Destination, typically using JNDI.
5 Use the Session to create a MessageConsumer for that Destination.

Как только вы это сделаете, методы на MessageConsumer позволит вам либо запросить адресат для сообщений или зарегистрироваться для уведомления о сообщении.

Может кто-нибудь, пожалуйста, направьте меня в правильном направлении, есть ли учебник, в котором подробно объясняется, как получать сообщения из очереди? У меня есть рабочий код отправки сообщения, я не публиковал его здесь, потому что это сообщение слишком длинное, поскольку оно является. РЕДАКТИРОВАТЬ:

Я добавил к своему jboss-сообщению destination-service.xml этот Mbean:

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

1 Ответ

3 голосов
/ 22 марта 2010

С вашего примера с примером Spring вы забыли:

<!-- 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="destination"/>
    <property name="messageListener" ref="messageListener" />
</bean>

Который соединяет очередь со слушателем:)

EDIT

Вы написали в комментариях:

but still I'm getting this error : org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'sender' defined in ServletContext resource [/WEB-INF/conf/applicationContext.xml]: Invocation of init method failed; nested exception is java.lang.NullPointerException

и

How does Example listener knows which queue to listen to anyways, I didn't specify to it, didn't know how

Первая проблема, я думаю, nullPointerException в строке jmsTemplate.convertAndSend. Ваш jmsTemplate не был инициализирован.

Я считаю, что это потому, что init-метод не является convertAndSend. Вам вообще не нужен init-метод. Вы должны установить свойства в applicationcontext.xml, примерно так:

<bean id="sender" class="quartz.spring.com.example.JmsQueueSender"> 
  <property name="queue" value="theNameOfYourQueue"> <!-- or in stead of value ref to a String which contains the shared queue name -->
  <property name="connectionFactory" ref="connectionFactory"/>
</bean>

Это должно исправить ошибки при отправке (кстати, почему вы используете JMSTemplate102, а не JMSTemplate?).

Другой вопрос, вы настраиваете имена очереди, устанавливая свойства в bean-компонентах. В этом случае вы, кажется, слушаете очередь queueDestination / ReceiverQueue, поскольку ваш jmsContainer настроен на обработку вызовов этой очереди вашим слушателем.

Где, черт возьми, это был бин messageListener, определенный в applicationcontext.xml?

если вы используете ref="someName" где-то, то также должно быть <bean name="someName" где-то.

EDIT

также посмотрите на этот пример , который, кажется, содержит немного больше кода конфигурации объяснил. Аргумент pubSubDomain имеет значение false, это означает, что это точка-точка:)

...