I followed a simple example of setting up and running embedded ActiveMQ with Spring Boot (version 1.4.X). Here's link to the example https://spring.io/guides/gs/messaging-jms/
My class is structured as below:
@SpringBootApplication
@EnableJms
public class Application {
@Autowired
ConfigurableApplicationContext context;
@Bean
JmsListenerContainerFactory<?> myJmsContainerFactory(ConnectionFactory connectionFactory) {
SimpleJmsListenerContainerFactory factory = new SimpleJmsListenerContainerFactory();
factory.setConnectionFactory(connectionFactory);
return factory;
}
@JmsListener(destination = "mailbox-destination", containerFactory = "myJmsContainerFactory")
public void receiveMessage(String message) {
System.out.println("Message received: " + message);
context.close();
}
public static void main(String[] args) throws Exception {
FileSystemUtils.deleteRecursively(new File("active-data"));
ConfigurableApplicationContext context = SpringApplication.run(Application.class, args);
JmsTemplate template = context.getBean(JmsTemplate.class);
MessageCreator messageCreator = new MessageCreator() {
public Message createMessage(Session session) throws JMSException {
return session.createTextMessage("Test");
}
};
template.send("mailbox-destination", messageCreator);
}
}
And build.gradle like below:
apply plugin: 'java'
apply plugin: 'maven'
group = 'jms.activemq'
version = '0.0.1-SNAPSHOT'
description = """jms.activemq"""
sourceCompatibility = 1.5
targetCompatibility = 1.5
repositories {
maven { url "http://repo.maven.apache.org/maven2" }
}
dependencies {
compile group: 'org.springframework.boot', name: 'spring-boot-starter-activemq', version:'1.4.0.RELEASE'
testCompile(group: 'org.springframework.boot', name: 'spring-boot-starter-test', version:'1.4.0.RELEASE') {
exclude(module: 'commons-logging')
}
}
Everything works well so far (as long as i leave the application.properties empty), but if i try to configure broker url (so remote clients can connect) by adding following to application.properties file:
spring.activemq.broker-url=tcp://localhost:61616
spring.activemq.user=admin
spring.activemq.password=admin
I get an exception:
2016-08-03 12:46:00.938 WARN 88180 --- [ main] s.c.a.AnnotationConfigApplicationContext : Exception encountered during context initialization - cancelling refresh attempt: org.springframework.context.ApplicationContextException: Failed to start bean 'org.springframework.jms.config.internalJmsListenerEndpointRegistry'; nested exception is org.springframework.jms.UncategorizedJmsException: Uncategorized exception occurred during JMS processing; nested exception is javax.jms.JMSException: Could not connect to broker URL: tcp://localhost:61616. Reason: java.net.ConnectException: Connection refused: connect
2016-08-03 12:46:00.939 INFO 88180 --- [ main] o.s.j.e.a.AnnotationMBeanExporter : Unregistering JMX-exposed beans on shutdown
2016-08-03 12:46:00.945 INFO 88180 --- [ main] utoConfigurationReportLoggingInitializer :
org.springframework.context.ApplicationContextException: Failed to start bean 'org.springframework.jms.config.internalJmsListenerEndpointRegistry'; nested exception is org.springframework.jms.UncategorizedJmsException: Uncategorized exception occurred during JMS processing; nested exception is javax.jms.JMSException: Could not connect to broker URL: tcp://localhost:61616. Reason: java.net.ConnectException: Connection refused: connect
at org.springframework.context.support.DefaultLifecycleProcessor.doStart(DefaultLifecycleProcessor.java:176) ~[spring-context-4.3.2.RELEASE.jar:4.3.2.RELEASE]
at org.springframework.context.support.DefaultLifecycleProcessor.access$200(DefaultLifecycleProcessor.java:51) ~[spring-context-4.3.2.RELEASE.jar:4.3.2.RELEASE]
at org.springframework.context.support.DefaultLifecycleProcessor$LifecycleGroup.start(DefaultLifecycleProcessor.java:346) ~[spring-context-4.3.2.RELEASE.jar:4.3.2.RELEASE]
at org.springframework.context.support.DefaultLifecycleProcessor.startBeans(DefaultLifecycleProcessor.java:149) ~[spring-context-4.3.2.RELEASE.jar:4.3.2.RELEASE]
at org.springframework.context.support.DefaultLifecycleProcessor.onRefresh(DefaultLifecycleProcessor.java:112) ~[spring-context-4.3.2.RELEASE.jar:4.3.2.RELEASE]
at org.springframework.context.support.AbstractApplicationContext.finishRefresh(AbstractApplicationContext.java:874) ~[spring-context-4.3.2.RELEASE.jar:4.3.2.RELEASE]
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:544) ~[spring-context-4.3.2.RELEASE.jar:4.3.2.RELEASE]
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:759) [spring-boot-1.4.0.RELEASE.jar:1.4.0.RELEASE]
at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:369) [spring-boot-1.4.0.RELEASE.jar:1.4.0.RELEASE]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:313) [spring-boot-1.4.0.RELEASE.jar:1.4.0.RELEASE]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1185) [spring-boot-1.4.0.RELEASE.jar:1.4.0.RELEASE]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1174) [spring-boot-1.4.0.RELEASE.jar:1.4.0.RELEASE]
at jms.activemq.Application.main(Application.java:37) [main/:na]
Caused by: org.springframework.jms.UncategorizedJmsException: Uncategorized exception occurred during JMS processing; nested exception is javax.jms.JMSException: Could not connect to broker URL: tcp://localhost:61616. Reason: java.net.ConnectException: Connection refused: connect
at org.springframework.jms.support.JmsUtils.convertJmsAccessException(JmsUtils.java:316) ~[spring-jms-4.3.2.RELEASE.jar:4.3.2.RELEASE]
at org.springframework.jms.support.JmsAccessor.convertJmsAccessException(JmsAccessor.java:169) ~[spring-jms-4.3.2.RELEASE.jar:4.3.2.RELEASE]
at org.springframework.jms.listener.AbstractJmsListeningContainer.start(AbstractJmsListeningContainer.java:273) ~[spring-jms-4.3.2.RELEASE.jar:4.3.2.RELEASE]
at org.springframework.jms.config.JmsListenerEndpointRegistry.startIfNecessary(JmsListenerEndpointRegistry.java:243) ~[spring-jms-4.3.2.RELEASE.jar:4.3.2.RELEASE]
at org.springframework.jms.config.JmsListenerEndpointRegistry.start(JmsListenerEndpointRegistry.java:206) ~[spring-jms-4.3.2.RELEASE.jar:4.3.2.RELEASE]
at org.springframework.context.support.DefaultLifecycleProcessor.doStart(DefaultLifecycleProcessor.java:173) ~[spring-context-4.3.2.RELEASE.jar:4.3.2.RELEASE]
... 12 common frames omitted
Caused by: javax.jms.JMSException: Could not connect to broker URL: tcp://localhost:61616. Reason: java.net.ConnectException: Connection refused: connect
at org.apache.activemq.util.JMSExceptionSupport.create(JMSExceptionSupport.java:36) ~[activemq-client-5.13.4.jar:5.13.4]
at org.apache.activemq.ActiveMQConnectionFactory.createActiveMQConnection(ActiveMQConnectionFactory.java:373) ~[activemq-client-5.13.4.jar:5.13.4]
at org.apache.activemq.ActiveMQConnectionFactory.createActiveMQConnection(ActiveMQConnectionFactory.java:303) ~[activemq-client-5.13.4.jar:5.13.4]
at org.apache.activemq.ActiveMQConnectionFactory.createConnection(ActiveMQConnectionFactory.java:243) ~[activemq-client-5.13.4.jar:5.13.4]
at org.springframework.jms.support.JmsAccessor.createConnection(JmsAccessor.java:180) ~[spring-jms-4.3.2.RELEASE.jar:4.3.2.RELEASE]
at org.springframework.jms.listener.AbstractJmsListeningContainer.createSharedConnection(AbstractJmsListeningContainer.java:413) ~[spring-jms-4.3.2.RELEASE.jar:4.3.2.RELEASE]
at org.springframework.jms.listener.AbstractJmsListeningContainer.establishSharedConnection(AbstractJmsListeningContainer.java:381) ~[spring-jms-4.3.2.RELEASE.jar:4.3.2.RELEASE]
at org.springframework.jms.listener.AbstractJmsListeningContainer.doStart(AbstractJmsListeningContainer.java:285) ~[spring-jms-4.3.2.RELEASE.jar:4.3.2.RELEASE]
at org.springframework.jms.listener.SimpleMessageListenerContainer.doStart(SimpleMessageListenerContainer.java:210) ~[spring-jms-4.3.2.RELEASE.jar:4.3.2.RELEASE]
at org.springframework.jms.listener.AbstractJmsListeningContainer.start(AbstractJmsListeningContainer.java:270) ~[spring-jms-4.3.2.RELEASE.jar:4.3.2.RELEASE]
... 15 common frames omitted
Caused by: java.net.ConnectException: Connection refused: connect
at java.net.DualStackPlainSocketImpl.waitForConnect(Native Method) ~[na:1.8.0_92]
at java.net.DualStackPlainSocketImpl.socketConnect(DualStackPlainSocketImpl.java:85) ~[na:1.8.0_92]
at java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:350) ~[na:1.8.0_92]
at java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:206) ~[na:1.8.0_92]
at java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:188) ~[na:1.8.0_92]
at java.net.PlainSocketImpl.connect(PlainSocketImpl.java:172) ~[na:1.8.0_92]
at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:392) ~[na:1.8.0_92]
at java.net.Socket.connect(Socket.java:589) ~[na:1.8.0_92]
at org.apache.activemq.transport.tcp.TcpTransport.connect(TcpTransport.java:525) ~[activemq-client-5.13.4.jar:5.13.4]
at org.apache.activemq.transport.tcp.TcpTransport.doStart(TcpTransport.java:488) ~[activemq-client-5.13.4.jar:5.13.4]
at org.apache.activemq.util.ServiceSupport.start(ServiceSupport.java:55) ~[activemq-client-5.13.4.jar:5.13.4]
at org.apache.activemq.transport.AbstractInactivityMonitor.start(AbstractInactivityMonitor.java:168) ~[activemq-client-5.13.4.jar:5.13.4]
at org.apache.activemq.transport.InactivityMonitor.start(InactivityMonitor.java:52) ~[activemq-client-5.13.4.jar:5.13.4]
at org.apache.activemq.transport.TransportFilter.start(TransportFilter.java:58) ~[activemq-client-5.13.4.jar:5.13.4]
at org.apache.activemq.transport.WireFormatNegotiator.start(WireFormatNegotiator.java:72) ~[activemq-client-5.13.4.jar:5.13.4]
at org.apache.activemq.transport.TransportFilter.start(TransportFilter.java:58) ~[activemq-client-5.13.4.jar:5.13.4]
at org.apache.activemq.transport.TransportFilter.start(TransportFilter.java:58) ~[activemq-client-5.13.4.jar:5.13.4]
at org.apache.activemq.ActiveMQConnectionFactory.createActiveMQConnection(ActiveMQConnectionFactory.java:353) ~[activemq-client-5.13.4.jar:5.13.4]
... 23 common frames omitted
I have looked at a few links and still not able to determine what is causing the issue. Would really appreciate some insight, or material that can help.
My initial thought was that Spring Boot will read these values and use them to configure ActiveMQ broker, but instead looks like it uses these values to connect to the broker (the broker having already been configured with different settings). How can I change the broker configuration so external clients (not running from with same JVM as the broker), can access the broker using tcp://localhost:61616
UPDATE:
I have followed one of the ways to embed a broker listed here and able to embed a broker with the required url and able to connect to it. However, it seems I end up having two brokers since it seems Spring Boot still goes ahead and create one as it did before.
Basically, am just adding this piece of code and at beginning of main method before calling SpringApplication.run(Application.class, args);
BrokerService broker = new BrokerService();
broker.addConnector("tcp://localhost:61617");
broker.setPersistent(false);
broker.start();
Doesn't feel right at all, having two broker instances(I believe) running.
1) Is this the proper way to embed a broker
2) If so, how can i stop Spring Boot from starting another one? (Without having to remove spring-boot-starter-activemq dependency).
Thanks in advance.
ActiveMq by default exposes a broker url tcp://localhost:61616 and an admin console on tcp://localhost:61616 with userId and password as admin and admin. Following are the steps to download and install activemq. 1. Download apache activemq from here as per your operating system.
An embedded broker can also be created using an ActiveMQConnectionFactory and using a vm connector as a uri. e.g. ActiveMQConnectionFactory cf = new ActiveMQConnectionFactory("vm://localhost?broker.persistent=false");
With Spring boot no boilerplate or configuration code is required. Download ActiveMQ from http://activemq.apache.org/download.html. Extract it. In the bin folder click on activemq.
I believe I figured this out after playing around with this for sometime. I thought two instances were running because I was trying to create a connection to the DEFAULT embedded broker (in an attempt to figure out if it was created/existed) like below:
ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory("vm://localhost?broker.persistent=false");
But apparently Spring Boot figures one doesn't exist and creates it at that time.
So in order to have only my created instance running, all I needed to do was provide a URL I added to the connector when I created the instance (in this case tcp://localhost:61616
) in the application.properties
file as below
spring.activemq.broker-url=tcp://localhost:61616
and Spring Boot will connect to this instance and not create another one. In the absence of the above entry in the properties file (or if you make an attempt to connect to an embedded instance using vm://localhost?... as I did above), Spring Boot will go ahead and instantiate one for you.
I did also read this in the documentation:
Spring Boot can also configure a ConnectionFactory when it detects that ActiveMQ is available on the classpath. If the broker is present, an embedded broker is started and configured automatically (as long as no broker URL is specified through configuration).
But in my opinion, it is not well spelled out (but it did get me thinking in the right direction though).
Please, do let know if you had different findings or if my conclusion isn't right. Thanks!!!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With