четверг, 1 ноября 2012 г.

Использование Spring для работы со встроенным HornetQ сервером

       В предыдущем посте рассматривался пример внедрения HornetQ сервера в приложение. Попробуем немного усовершенствовать его, переложив часть работы на Spring.
       Необходимо подключить к проекту spring-jms.jar, после чего добавить немного кода в конфиг Spring
Это наш встроенный HornetQ сервер, он будет стартовать и останавливаться автоматически при поднятии контекста.

<bean class="org.hornetq.jms.server.embedded.EmbeddedJMS"
    destroy-method="stop"
     id="jmsServer"
     init-method="start"/>

Локатор ConnecitonFactory. Этот класс возвращает экземпляр ConnecitonFactory. Обычно ConnecitonFactory биндится на JNDI, но не в нашем случае, так что требуется специальный класс для того, чтобы получить ее.

 <bean class="example.jms.JmsConnecitonFactoryLocator"
                         depends-on="jmsServer"
                         factory-method="lookupConnectionFactory"
                         id="jmsConnectionFactory">
      <constructor-arg= name="server" ref="jmsServer" />
</bean>

Это стандартный JMSTemplate, с его помошью мы будет отсылать сообщения в очередь

<bean class="org.springframework.jms.core.JmsTemplate"
                         depends-on="jmsServer"
                         id="jmsQueueTemplate">
        <property name="connectionFactory">
            <ref bean="jmsConnectionFactory"/>
        </property>    
</bean>
JmsQueueLocator - класс-фабрика для получения экземпляра очереди. Необходим для того, чтобы организовать приемник сообщений.


<bean class="example.jms.JmsQueueLocator"
               depends-on="jmsServer"
               factory-method="lookupQueue"
               id="paymentQueue">
        <constructor-arg name="server" ref="jmsServer" />
        <constructor-arg name="queueName" value="queue/paymentQueue" />
</bean>
Собственно класс, отвественный за получение сообщений. Поддерживает несколько конкурентных получателей.Обратите внимание на ref="transactionPusher". Данный бин определяется в коде посредством аннотации @Component(value = "transactionPusher")


<bean id="jmsContainerPayment"  
            class="org.springframework.jms.listener.DefaultMessageListenerContainer">
        <property name="connectionFactory" ref="jmsConnectionFactory"/>
        <property name="destination" ref="paymentQueue"/>
        <property name="messageListener" ref="transactionPusher" />
        <property name="concurrentConsumers" value="5"/>
</bean>


Теперь код:
Класс-фабрика для получения соединения с нашим встроенным JMS сервером

public class JmsConnecitonFactoryLocator {
    private static final Logger logger = LoggerFactory.getLogger(JmsConnecitonFactoryLocator.class);

    public static HornetQJMSConnectionFactory lookupConnectionFactory(EmbeddedJMS server){
        HornetQJMSConnectionFactory cf = (HornetQJMSConnectionFactory) server.lookup("ConnectionFactory");
        if(cf == null){
            logger.error("connection factory is null");
        }else{
            logger.info("connection factory is not null");
        }
        return cf;
    }
}


Класс-фабрика для получения экземпляра очереди

public class JmsQueueLocator {
    public static Queue lookupQueue(EmbeddedJMS server, String queueName){
        return (Queue) server.lookup(queueName);
    }
}


Класс - приемник сообщений


@Component(value = "transactionPusher")
public class TransactionPusher implements MessageListener {
    private static final Logger logger = LoggerFactory.getLogger(TransactionPusher.class);

    @Override
    public void onMessage(Message message) {

       try{
            TextMessage m = (TextMessage)message;
            m.acknowledge(); // говорим, что успешно приняли сообщение.
            // сделать что-то полезное
        } catch (JMSException e) {  

            logger.error("JMS exceptoin: ", e);
        }
    }
}


Пример использования JMSTemplate для отсылки сообщений:

public void addPaymentToQueue(final Transaction t) throws JMSException {
        jmsTemplate.send(paymentQueue, new MessageCreator() {
            @Override
            public Message createMessage(Session session) throws JMSException {
                TextMessage msg = session.createTextMessage();
                msg.setText(String.valueOf(t.getId()));
                return msg;
            }
        });
}


     Как можно заметить, Spring берет на себя значительную часть работы по организации рутинных операций, позволяя сосредоточиться на программировании бизнес логики приема и отправки сообщений. Класс DefaultMessageListenerContainer позволяет настраивать количество конкурентных потребителей, а также динамически увеличивать количество потребителей при увеличении нагрузки.





Комментариев нет:

Отправить комментарий