ActiveMQ autoconfiguration with spring integration
In current versions, spring boot can also configure the ConnectionFactory when it detects that ActiveMQ is available on the classpath. If a broker is present, the built-in broker is started and configured automatically.
This is similar to using a JMSTemplate. If I want to use the automatic configuration of spring integration, then unfortunately this does not work. It seems that ActiveMQ is configured after spring integration. spring loads error messages for a missing factory connection. I am using spring boot version 1.1.4 and latest spring integration for this.
I am getting this stack from spring boot:
2014-08-08 09:24:21.050 ERROR 6728 --- [ main]
o.s.boot.SpringApplication : Application startup failed
org.springframework.beans.factory.BeanCreationException: Error creating bean with name
'org.springframework.integration.jms.JmsSendingMessageHandler#0':
Cannot create inner bean '(inner bean)#54930080' of type
[org.springframework.integration.jms.DynamicJmsTemplate] while setting constructor
argument; nested exception is org.springframework.beans.factory.BeanCreationException:
Error creating bean with name '(inner bean)#54930080': Cannot resolve reference to
bean 'connectionFactory' while setting bean property 'connectionFactory'; nested
exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean
named 'connectionFactory' is defined
at
org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveInnerBean(
BeanDefinitionValueResolver.java:290)
at
org.springframework.beans.factory.support.BeanDefinitionValueResolver.
resolveValueIfNecessary(BeanDefinitionValueResolver.java:129)
It seems to me that the dependencies in spring boot configurations are wrong regarding the spring and jms integration pattern. The default JMS auto configuration looks like this:
@ConditionalOnClass(JmsTemplate.class)
@ConditionalOnBean(ConnectionFactory.class)
@EnableConfigurationProperties(JmsProperties.class)
@AutoConfigureAfter({ HornetQAutoConfiguration.class,
ActiveMQAutoConfiguration.class })
public class JmsAutoConfiguration
Spring integration looks like this:
@Configuration
@ConditionalOnClass(EnableIntegration.class)
@AutoConfigureAfter(JmxAutoConfiguration.class)
public class IntegrationAutoConfiguration {
There shouldn't be any kind of automatic configuration for the dynamic jms template the spring integration creates with respect to the factory connection and the active mq. If you think spring boot ref docs would I expect correct auto-configuration with jms for spring integration?
source to share
Good - it worked. This is a mistake (I think).
ActiveMQConnectionFactoryConfiguration creates a bean called "jmsConnectionFactory" but looking at your stack (above) Spring Integration looks for a bean for the name: 'connectionFactory'
Edit: INT-3941 is open
Workaround:
@Configuration
public static class SpringBootVsIntegraionWorkaround {
@Autowired
GenericApplicationContext genericApplicationContext;
@PostConstruct
public void init() {
genericApplicationContext.registerAlias("jmsConnectionFactory", "connectionFactory");
}
}
source to share
I have reproduced this issue. Here's an example:
Before (to show everything works):
@SpringBootApplication
public class HelloWorldSiActivemqApplication {
public static void main(String[] args) {
SpringApplication.run(HelloWorldSiActivemqApplication.class, args);
}
@Service
public static class SayHelloService {
@Autowired
ConnectionFactory connectionFactory;
public void sayHello(String name){
System.out.println("JMS Connection Factory: " + connectionFactory);
System.out.println("## Hello " + name + "!!!" );
}
}
@Component
public static class HelloListener {
@Autowired
SayHelloService sayHelloService;
@JmsListener(destination="helloJMSQueue")
public void sayHello(String name){
sayHelloService.sayHello(name);
}
}
}
application.properties
spring.activemq.broker-url=tcp://0.0.0.0:61613
spring.activemq.user=admin
spring.activemq.password=password
This works great. When I hit the JMS endpoint with a unit test I get:
JMS Connection Factory: org.apache.activemq.ActiveMQConnectionFactory@4b137f92
## Hello SayHelloServiceTest!!!
However, when I enter Spring Integration:
@ImportResource("classpath*:/spring/si-config.xml")
ci-config.xml
<jms:message-driven-channel-adapter id="helloJMSAdapater" destination="helloJMSQueue"
channel="helloChannel"/>
<integration:channel id="helloChannel"/>
.. and run my test again:
No bean named 'connectionFactory' is defined
Hope this helps!
source to share