How to get Spring to connect my JmsComponent

I am writing an application using Akka, Akka-Camel and Spring for configuration. The application should act as a stand-alone JMS client for various application servers, for which it needs to configure the JMS connection factory using JNDI. I am testing this with jBoss. I have the same problem with jBoss 5 and 6 (this seems to be a Spring client problem not related to jBoss).

I am configuring Spring beans with this xml:

<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:camel="http://camel.apache.org/schema/spring" xmlns:jee="http://www.springframework.org/schema/jee" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://camel.apache.org/schema/spring http://camel.apache.org/schema/spring/camel-spring.xsd http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-3.0.xsd "> <camelContext id="camel" trace="false" xmlns="http://camel.apache.org/schema/spring"> <jmxAgent id="agent" disabled="true"/> </camelContext> <jee:jndi-lookup id="jmsConnectionFactory" jndi-name="ConnectionFactory"> <jee:environment> java.naming.factory.initial=org.jnp.interfaces.NamingContextFactory java.naming.factory.url.pkgs=org.jboss.naming:org.jnp.interfaces java.naming.provider.url=jnp://192.168.0.109:1099 </jee:environment> </jee:jndi-lookup> <bean name="jms" class="org.apache.camel.component.jms.JmsComponent"> <property name="connectionFactory" ref="jmsConnectionFactory" /> </bean> </beans> 

As you can see, I am setting up:

  • ConnectionFactory initialized via JNDI is called jmsConnectionFactory
  • JmsComponent component with connectionFactory property set in previous bean

In this configuration, my application does not work at startup using this:

 java.lang.IllegalArgumentException: connectionFactory must be specified at org.apache.camel.util.ObjectHelper.notNull(ObjectHelper.java:294) ~[camel-core.jar:2.10.4] at org.apache.camel.component.jms.JmsConfiguration.createConnectionFactory(JmsConfiguration.java:1053) ~[camel-jms.jar:2.10.4] at org.apache.camel.component.jms.JmsConfiguration.getConnectionFactory(JmsConfiguration.java:416) ~[camel-jms.jar:2.10.4] at org.apache.camel.component.jms.JmsConfiguration.createListenerConnectionFactory(JmsConfiguration.java:1062) ~[camel-jms.jar:2.10.4] at org.apache.camel.component.jms.JmsConfiguration.getListenerConnectionFactory(JmsConfiguration.java:435) ~[camel-jms.jar:2.10.4] at org.apache.camel.component.jms.JmsConfiguration.configureMessageListenerContainer(JmsConfiguration.java:889) ~[camel-jms.jar:2.10.4] at org.apache.camel.component.jms.JmsConfiguration.createMessageListenerContainer(JmsConfiguration.java:379) ~[camel-jms.jar:2.10.4] 

This comes from this code in JmsConfiguration.java:

 protected ConnectionFactory createConnectionFactory() { ObjectHelper.notNull(connectionFactory, "connectionFactory"); return null; } 

So, it looks like the initialization of Spring beans cannot bind / connect beans, as indicated here (extracted from Spring's fully saved XML configuration):

  <bean name="jms" class="org.apache.camel.component.jms.JmsComponent"> <property name="connectionFactory" ref="jmsConnectionFactory" /> </bean> 

I also tried to create an intermediate JmsConfiguration bean and set the JmsComponent configuration property, instead of setting the connectionFactory property directly, but I get the same result in both settings.

By the way, I can connect beans by code. I mean this:

 val connFactory = springContext.getBean[javax.jms.ConnectionFactory]("jmsConnectionFactory", classOf[javax.jms.ConnectionFactory]) camelContext.addComponent("jms", JmsComponent.jmsComponentAutoAcknowledge(connFactory)) 

works great. So I know that I get ConnectionFactory from JNDI, I just can't get into the correct Spring configuration to bind it in XML.

I need this application to be very customizable without recompiling, so getting XML to work is a must for me.

In case this is unclear, the question arises: how do I get Spring to configure my JmsComponent bean, with its connectionFactory set to a JNDI-received factory?

EDIT: Camel's point of use is that it should allow me to exchange this component even for another other type. So today I use JMS, maybe tomorrow I will use TCP. That's why it would be important to be able to define everything in XML.

+2
source share
2 answers

I believe the problem is that Akka uses its own CamelContext, not the one defined in the Spring configuration. In earlier versions of Akka, it seemed possible to establish the context used by Akka , but this was no longer possible in recent versions.

I ran into the same problem, I use annotation-based configuration in Java (not Scala), and circumvented the problem with this code:

 @Bean public ActorSystem getCamelActorSystem(ConnectionFactory factory) { ActorSystem system = ActorSystem.create("some-system"); Camel camel = CamelExtension.get(system); CamelContext camelContext = camel.context(); camelContext.addComponent("jms", JmsComponent.jmsComponentAutoAcknowledge(factory)); return system; } 

This introduces the ConnectionFactory dependency defined elsewhere, and uses this to add the jms component to the camelContext that Akka uses.

Another solution might be to somehow extend the CamelExtension code to allow camelContext injection as previously possible. However, I assume that they have good reasons for change, and therefore leave it alone. I think that they can guarantee that the context cannot be changed, therefore the Actor system always uses the same Camel context, this is based on the following:

One instance of CamelExtension is loaded only once for each ActorSystem, which allows you to safely call CamelExtension anywhere in your code to access its associated Apache Camel objects. There is one CamelContext and one ProducerTemplate for each ActorSystem that uses CamelExtension.

http://doc.akka.io/docs/akka/current/scala/camel.html#CamelExtension

+1
source

Since your search works, this is probably more than what you are looking for, but here is how I get the factory connection via jndi using jndiTemplate (spring 3.1). Please note that I am providing a factory solution through configuration (via transaction manager). Sorry for any typos, but you get this idea.

 <bean id="jndiDestinationResolver" class="org.springframework.jms.support.destination.JndiDestinationResolver"/> <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"> <property name="location"> <value>classpath:connection.properties</value> </property> </bean> <bean name="jms" class="org.apache.camel.component.jms.JmsComponent"> <property name="configuration" ref="jmsConfig" /> </bean> <bean id="txManager" class="org.springframework.jms.connection.JmsTransactionManager"> <property name="connectionFactory" ref="springConnectionFactory"/> <bean> <bean id="jmsConfig" class="org.apache.camel.component.jms.JmsConfiguration"> <property name="connectionFactory" ref="springConnectionFactory" /> <property name="transactionManager" ref="txManager" /> <property name="testConnectionOnStartup" value="true" /> <property name="destinationResolver" ref="jndiDestinationResolver" /> </bean> <bean id="springConnectionFactory" class="org.springframework.jms.connection.CachingConnectionFactory"> <property name="clientId" ref="SubCid" /> <property name="reconnectOnException" ref="true" /> <property name="targetConnectionFactory"> <bean parent="jndiObjectFactory"/> </property> <property name="sessionCacheSize" value="1"/> </bean> <bean id="jndiObjectFactory" class="org.springframework.jndi.JndiObjectFactoryBean"> <property name="jndiName" value="TopicConnectionFactory"/> <property name="jndiTemplate"> <ref bean="jndiTemplate"/> </property> </bean> <bean id="jndiTemplate" class="org.springframework.jndi.JndiTemplate"> <property name="environment"> <props> <prop key="java.naming.provider.url">${db.jms.JNDIServerName}</prop> </props> </property> </bean> 
0
source

All Articles