Как инициализировать ConnectionFactory для удаленной очереди JMS, когда удаленная машина не запущена? - PullRequest
5 голосов
/ 24 августа 2009

Используя JBoss 4.0.5, JBossMQ и Spring 2.0.8, я пытаюсь настроить Spring для создания экземпляров bean-компонентов, которые зависят от удаленного ресурса JMS Queue. Все примеры, с которыми я сталкивался, зависят от использования JNDI для поиска таких вещей, как удаленный объект ConnectionFactory.

Моя проблема заключается в том, что при попытке вызвать компьютер, который поместил бы сообщения в удаленную очередь, если удаленный компьютер не запущен, поиск JNDI просто завершается сбоем, вызывая сбой развертывания. Есть ли способ заставить Spring продолжать поиск этого объекта в фоновом режиме, не блокируя оставшуюся часть развертывания?

Ответы [ 2 ]

3 голосов
/ 24 августа 2009

Трудно быть уверенным, не увидев конфигурацию Spring, но если вы используете JndiObjectFactoryBean Spring для выполнения поиска JNDI, тогда вы можете установить для свойства lookupOnStartup значение false, что позволяет контексту запускаться даже если цель JNDI не существует. Разрешение JNDI будет выполнено при первом использовании ConnectionFactory.

Однако это только сдвигает проблему дальше по цепочке, потому что, если какой-то другой компонент попытается получить JMS Connection при запуске, вы вернетесь к тому, с чего начали. Вы можете использовать атрибут lazy-init="true" на других bean-компонентах, чтобы предотвратить это при развертывании, но вы легко можете случайно вставить что-то в вашу конфигурацию, что заставит все инициализироваться.

1 голос
/ 25 августа 2009

Ты абсолютно прав. Я попытался установить для lookupOnStartup значение false и lazy-init = true. Это просто переносит проблему на первый раз, когда пытаются использовать очередь. Затем выдается следующее исключение:

[org.jboss.mq.il.uil2.SocketManager] Failed to handle: org.jboss.mq.il.uil2.msgs.CloseMsg29702787[msgType: m_connectionClosing, msgID: -2147483606, error: null]
java.io.IOException: Client is not connected

Более того, похоже, что поиск никогда больше не предпринимается. Когда машина с удаленной очередью восстанавливается, никакие сообщения не обрабатываются впоследствии. Это действительно кажется, что это должно быть хорошо в пределах диапазона вариантов использования для чепухи J2EE, и все же мне не очень повезло ... Такое ощущение, что это может быть даже решенная проблема. 1006 *

Для завершения ниже приведена соответствующая часть моей конфигурации Spring.

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

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

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

    <bean id="remoteConnectionFactory" class="org.springframework.jndi.JndiObjectFactoryBean" lazy-init="true">
        <property name="jndiTemplate" ref="remoteJndiTemplate"/>
        <property name="jndiName" value="ConnectionFactory" />
        <property name="lookupOnStartup" value="false" />
        <property name="proxyInterface" value="javax.jms.ConnectionFactory" />
    </bean>

    <bean id="destinationResolver" class="com.foo.jms.FooDestinationResolver" />

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

    <bean id="globalVoicemailTranscodingDestination" class="org.springframework.jndi.JndiObjectFactoryBean" lazy-init="true" >
        <property name="jndiTemplate" ref="remoteJndiTemplate" />
        <property name="jndiName" value="queue/globalVoicemailTranscoding" />
    </bean>

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

    <bean id="remoteJmsTemplate" class="org.springframework.jms.core.JmsTemplate" lazy-init="true">
        <property name="connectionFactory" ref="remoteConnectionFactory"/>
        <property name="destinationResolver" ref="destinationResolver"/>
    </bean>

    <bean id="globalQueueStatus" class="com.foo.bar.recording.GlobalQueueStatus" />

    <!-- Do not deploy this bean for machines other than transcoding machine -->
    <condbean:cond test="${transcoding.server}">
        <bean id="voicemailMDPListener"
              class="org.springframework.jms.listener.adapter.MessageListenerAdapter" lazy-init="true">
            <constructor-arg>
                <bean class="com.foo.bar.recording.mdp.VoicemailMDP" lazy-init="true">
                    <property name="manager" ref="vmMgr" />
                </bean>
            </constructor-arg>
        </bean>
    </condbean:cond>

    <bean id="voicemailForwardingMDPListener"
          class="org.springframework.jms.listener.adapter.MessageListenerAdapter" lazy-init="true">
        <constructor-arg>
            <bean class="com.foo.bar.recording.mdp.QueueForwardingMDP" lazy-init="true">
                <property name="queueStatus" ref="globalQueueStatus" />
                <property name="template" ref="remoteJmsTemplate" />
                <property name="remoteDestination" ref="globalVoicemailTranscodingDestination" />
            </bean>
        </constructor-arg>
    </bean>

    <bean id="prototypeListenerContainer"
          class="org.springframework.jms.listener.DefaultMessageListenerContainer"
          abstract="true"
          lazy-init="true">
        <property name="concurrentConsumers" value="5" />
        <property name="connectionFactory" ref="connectionFactory" />
        <!-- 2 is CLIENT_ACKNOWLEDGE: http://java.sun.com/j2ee/1.4/docs/api/constant-values.html#javax.jms.Session.CLIENT_ACKNOWLEDGE -->
        <!-- 1 is autoacknowldge -->
        <property name="sessionAcknowledgeMode" value="1" />
        <property name="sessionTransacted" value="true" />
     </bean>

     <!-- Do not deploy this bean for machines other than transcoding machine -->
     <condbean:cond test="${transcoding.server}">
         <bean id="voicemailMDPContainer" parent="prototypeListenerContainer" lazy-init="true">
           <property name="destination" ref="globalVoicemailTranscodingDestination" />
           <property name="messageListener" ref="voicemailMDPListener" />
         </bean>
     </condbean:cond>

     <bean id="voicemailForwardMDPContainer" parent="prototypeListenerContainer" lazy-init="true">
       <property name="destination" ref="localVoicemailTranscodingDestination" />
       <property name="messageListener" ref="voicemailForwardingMDPListener" />
     </bean>
...