Spring Boot embedded ActiveMQ Artemis JMS broker behaviour
Asked Answered
K

3

15

I've been struggling lately with the spring-boot-artemis-starter. My understanding of its Spring Boot support was the following:

  • set spring.artemis.mode=embedded and, like Tomcat, Spring Boot will instantiate a broker reachable through TCP (server mode). The following command should be successful: nc -zv localhost 61616
  • set spring.artmis.mode=native and Spring Boot will only configure the jms template according to the spring.artemis.* properties (client mode).

The client mode works just fine with a standalone ActiveMQ Artemis server on my machine. Unfortunately, I could never manage to reach the TCP port in server mode.

I would be grateful if somebody confirms my understanding of the embedded mode.

After some digging I noted that the implementation provided out of the box by the spring-boot-starter-artemis uses org.apache.activemq.artemis.core.remoting.impl.invm.InVMAcceptorFactory acceptor. I'm wondering if that's not the root cause (again I'm by no means an expert). But it appears that there is a way to customize artemis configuration. Therefore I tried the following configuration without any luck:

@SpringBootApplication
public class MyBroker {

    public static void main(String[] args) throws Exception {
        SpringApplication.run(MyBroker.class, args);
    }

    @Autowired
    private ArtemisProperties artemisProperties;

    @Bean
    public ArtemisConfigurationCustomizer artemisConfigurationCustomizer() {
        return configuration -> {
            try {
               configuration.addAcceptorConfiguration("netty", "tcp://localhost:" + artemisProperties.getPort());
            } catch (Exception e) {
                throw new RuntimeException("Failed to add netty transport acceptor to artemis instance");
            }
        };
    }
}
Krefeld answered 30/9, 2016 at 11:52 Comment(0)
H
14

You just have to add a Connector and an Acceptor to your Artemis Configuration. With spring-boot-artemis-starter Spring creates a configuration bean which will be used for EmbeddedJMS configuration. You can see this in ArtemisEmbeddedConfigurationFactory where an InVMAcceptorFactory will be set for the configuration. You can edit this bean and change ActiveMQ Artemis' behaviour through custom ArtemisConfigurationCustomizer bean which will be sucked up by Spring autoconfig and be applied to the configuration.

An example config class for your Spring Boot application:

import org.apache.activemq.artemis.api.core.TransportConfiguration;
import org.apache.activemq.artemis.core.remoting.impl.netty.NettyAcceptorFactory;
import org.apache.activemq.artemis.core.remoting.impl.netty.NettyConnectorFactory;
import org.springframework.boot.autoconfigure.jms.artemis.ArtemisConfigurationCustomizer;
import org.springframework.context.annotation.Configuration;

@Configuration
public class ArtemisConfig implements ArtemisConfigurationCustomizer {
    @Override
    public void customize(org.apache.activemq.artemis.core.config.Configuration configuration) {
        configuration.addConnectorConfiguration("nettyConnector", new TransportConfiguration(NettyConnectorFactory.class.getName()));
        configuration.addAcceptorConfiguration(new TransportConfiguration(NettyAcceptorFactory.class.getName()));
    }
}
Homicidal answered 19/3, 2017 at 10:56 Comment(0)
H
8

My coworker and I had the exact same problem as the documentation on this link (chapter Artemis Support) says nothing about adding an individual ArtemisConfigurationCustomizer - Which is sad because we realized that without this Customizer our Spring Boot App would start and act as if everything was okay but actually it wouldn't do anything.

We also realized that without the Customizer the application.properties file is not beeing loaded so no matter what host or port you mentioned there it would not count.

After adding the Customizer as stated by the two examples it worked without a problem.

Here some results that we figured out:

  • It only loaded the application.properties after configuring an ArtemisConfigurationCustomizer

  • You don't need the broker.xml anymore with an embedded spring boot artemis client

  • Many examples showing the use of Artemis use a "in-vm" protocol while we just wanted to use the netty tcp protocol so we needed to add it into the configuration

  • For me the most important parameter was pub-sub-domain as I was using topics and not queues. If you are using topics this parameter needs to be set to true or the JMSListener won't read the messages.

See this page: stackoverflow jmslistener-usage-for-publish-subscribe-topic

When using a @JmsListener it uses a DefaultMessageListenerContainer which extends JmsDestinationAccessor which by default has the pubSubDomain set to false. When this property is false it is operating on a queue. If you want to use topics you have to set this properties value to true.

In Application.properties:
spring.jms.pub-sub-domain=true

If anyone is interested in the full example I have uploaded it to my github: https://github.com/CorDharel/SpringBootArtemisServerExample

Hamilton answered 14/7, 2017 at 14:31 Comment(0)
I
2

The embedded mode starts the broker as part of your application. There is no network protocol available with such setup, only InVM calls are allowed. The auto-configuration exposes the necessary pieces you can tune though I am not sure you can actually have a TCP/IP channel with the embedded mode.

Insectarium answered 30/9, 2016 at 12:38 Comment(6)
Thank you @Sephane Nicoll. There must be reasons for that. It does not solve my use case but I'll deal with it.Krefeld
To be clear, I am a member of the Spring Boot team and I am happy to revisit that use case if it makes sense. I am just not sure it does right now. If you want to access the broker externally (via TCP/IP) you shouldn't embed it IMO.Insectarium
Well to me it's the same use case as the web container. I chose spring-boot because it provides production ready features for the web container. What if I want the same features for my broker: I encapsulate it with spring-boot and voila. I benefit from all nice features including linux service support, health check, etc. Also no dev has to install it and configure it on its machine, it's already provided. Anyway I rolled back to activemq wich provides a way to start a tcp broker and encapsulated it with spring boot in my IT test. Now all IT components start the same way: java -jar ...Krefeld
I disagree. Are you going in prod with an H2 embedded database? A JMS broker is meant to be accessed by several components with high availability in production. I guess there's a reason why Artemis doesn't expose the feature as ActiveMQ doe...Insectarium
The link is deadHidebound
Thanks @StephaneNicoll for responding. I totally agree for a production use case but I have a new use cases to expose: 1/ I want to test my STOMP client against a Artemis server & debug inside my IDE, without the needs to setup/install a "real artemis broker" 2/ I want to have integration tests against Artemis server in my test suite, for my CI/CD without the needs to install a real artemis broker 3/I want to develop & test a Custom Module for Artemis. For all those cases I need a TCP/WS connection, not InVm. And because my tool suite is Spring, I would love to use spring-boot-starter-artemis.Charbonneau

© 2022 - 2024 — McMap. All rights reserved.