2010-12-10 35 views
3

J'ai configuré une configuration de ressort pour JMS. Les choses fonctionnent bien, sauf que je n'arrive pas à l'obtenir en chargement paresseux (notez le default-lazy-init vrai dans le code ci-dessous). Si je commente le jmsContainer (DMLC) de ma config ci-dessous, le chargement paresseux fonctionne comme prévu. Sinon, il va instancier le DMLC, qui à son tour crée la file d'attente et la fabrique de connexions.Printemps 3.0 paresseux-init pas honoré pour DefaultMessageListenerContainer?

Qu'est-ce qui me manque?

jmsContext.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:p="http://www.springframework.org/schema/p" 
     xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd" 
     default-lazy-init="true"> 

    <bean id="jndiTemplate" class="org.springframework.jndi.JndiTemplate"> 
     <property name="environment"> 
      <props> 
       <prop key="java.naming.factory.initial">weblogic.jndi.WLInitialContextFactory</prop> 
       <prop key="java.naming.provider.url">t3:localhost:7001</prop> 
      </props> 
     </property> 
    </bean> 

    <bean id="queue" class="org.springframework.jndi.JndiObjectFactoryBean" 
      p:jndiTemplate-ref="jndiTemplate" p:jndiName="jms/queue"/> 

    <bean id="connectionFactory" class="org.springframework.jndi.JndiObjectFactoryBean" 
      p:jndiTemplate-ref="jndiTemplate" p:jndiName="jms/connectionfactory"/> 

    <bean id="jmsDestinationResolver" class="org.springframework.jms.support.destination.JndiDestinationResolver" 
     p:jndiTemplate-ref="jndiTemplate" p:cache="true" /> 

    <bean id="jmsContainer" class="org.springframework.jms.listener.DefaultMessageListenerContainer" 
      p:autoStartup="false" 
      p:destination-ref="queue" 
      p:destinationResolver-ref="jmsDestinationResolver" 
      p:connectionFactory-ref="connectionFactory" 
      p:messageListener-ref="queueListener" /> 

    <bean id="queueListener" class="com.blah.QueueListener"/> 


</beans> 

Et le test que je utilise pour conduire, DummyTest.java:

package blah; 

import org.junit.Test; 
import org.junit.runner.RunWith; 
import org.springframework.test.context.ContextConfiguration; 
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; 

@RunWith(SpringJUnit4ClassRunner.class) 
@ContextConfiguration("classpath:jmsContext.xml") 
public class DummyTest { 

    @Test 
    public void shouldDoSomething() { 

    } 

} 

Lorsque jmsContainer est commentée, le test passe au-dessus. Sinon, je reçois ceci:

java.lang.IllegalStateException: Failed to load ApplicationContext 
Caused by: org.springframework.beans.factory.BeanCreationException: 
Error creating bean with name 'jmsContainer' defined in class path resource [com/blah/config/jmsContext.xml]: 
Cannot resolve reference to bean 'connectionFactory' while setting bean property 'connectionFactory'; 
nested exception is org.springframework.beans.factory.BeanCreationException: 
Error creating bean with name 'connectionFactory' defined in class path resource [com/blah/config/jmsContext.xml]: 
Invocation of init method failed; nested exception is javax.naming.NameNotFoundException: 
Exception in lookup.: `jms/connectionfactory' could not be found. 
[Root exception is weblogic.corba.cos.naming.NamingContextAnyPackage.NotFound: IDL:weblogic/corba/cos/naming/NamingContextAny/NotFound:1.0] 

Le « connectionFactory » haricot obtient instancié comme une dépendance de « jmsContainer » et il tombe en panne. Avec "jmsContainer" commenté, "connectionFactory" n'est pas instancié. Le code jms fonctionne bien, mais j'ai renommé mes noms JNDI pour que je puisse voir quand les choses ont commencé.

+0

Êtes-vous absolument sûr que ça démarrage? Quelle est la preuve? Pouvez-vous intégrer cette preuve dans votre test? – skaffman

+2

Pour (ma) prospérité future: La création de Bean et le démarrage de conteneurs d'écoute sont des choses différentes. p: autoStartup = "false" empêchera le démarrage du conteneur d'écoute, bien que ses références de beans doivent être résolues. Si vous avez d'autres beans comme JmsMessageDrivenEndpoint qui implémentent SmartLifeCycle, ceux-ci doivent aussi avoir autoStartup = "false", sinon ils démarreront le conteneur d'écoute – Patrick

+0

+1 pour la mention isAutoStartup. C'était mon problème lors de la tentative de chargement de SimpleMessageContextListener pour AMQP. – alph486

Répondre

4

OK, cela est assez obscur, mais DefaultMessageListenerContainer implémente l'interface Lifecycle, et les haricots qui mettent en œuvre ce sont liés en propre cycle de vie du contexte - lorsque le contexte démarre, Lifecycle les haricots sont initialisés et -Mise en oeuvre a commencé. Cela signifie que votre configuration lazy-init est essentiellement ignorée.

+1

En fait, c'est l'interface SmartLifecycle: http://static.springsource.org/spring/docs/3.0.x/javadoc-api/org/springframework/context/SmartLifecycle.html. Il doit être instancié afin que Spring puisse appeler isAutoStartup pour déterminer s'il doit être démarré. – cavey79

0

La solution consiste à utiliser autoStartup à false. Voir le code ci-dessous.

<bean id="listenerContainer" 
    class="org.springframework.jms.listener.DefaultMessageListenerContainer"> 
    ........ 
    <property name="autoStartup" value="false"/> 
</bean> 

~ Shyam