Skip to content

Allow to configure ActiveMQ Artemis using broker url #24302

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
* @author Eddú Meléndez
* @author Phillip Webb
* @author Stephane Nicoll
* @author Justin Bertram
*/
class ArtemisConnectionFactoryFactory {

Expand Down Expand Up @@ -127,13 +128,21 @@ private <T extends ActiveMQConnectionFactory> T createEmbeddedConnectionFactory(

private <T extends ActiveMQConnectionFactory> T createNativeConnectionFactory(Class<T> factoryClass)
throws Exception {
T connectionFactory;
Map<String, Object> params = new HashMap<>();
params.put(TransportConstants.HOST_PROP_NAME, this.properties.getHost());
params.put(TransportConstants.PORT_PROP_NAME, this.properties.getPort());
TransportConfiguration transportConfiguration = new TransportConfiguration(
NettyConnectorFactory.class.getName(), params);
Constructor<T> constructor = factoryClass.getConstructor(boolean.class, TransportConfiguration[].class);
T connectionFactory = constructor.newInstance(false, new TransportConfiguration[] { transportConfiguration });
String url = this.properties.getBrokerUrl();
if (StringUtils.hasText(url)) {
Constructor<T> constructor = factoryClass.getConstructor(String.class);
connectionFactory = constructor.newInstance(url);
}
else {
params.put(TransportConstants.HOST_PROP_NAME, this.properties.getHost());
params.put(TransportConstants.PORT_PROP_NAME, this.properties.getPort());
TransportConfiguration transportConfiguration = new TransportConfiguration(
NettyConnectorFactory.class.getName(), params);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about this transport configuration that we se to NettyConnectionFactory?

@wilkinsona mentioned that on the original issue and we'd like some feedback on that.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought I had already addressed that concern. To be clear, I don't really see what the concern actually is. The URL and all of its parameters are turned into a TransportConfiguration behind the scenes. Everything that can be set directly via a TransportConfiguration can be set with URL parameters. In other words there is no "loss of control" that I can see as @wilkinsona mentioned.

This change makes the Artemis integration essentially equivalent to the ActiveMQ 5.x integration which in my opinion is how it should have been implemented in the first place.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As far as I can see you did not hence why I am asking here. The code I've referenced makes an explicit setup using NettyConnectorFactory. As far as I can see we'd lose that as soon as an url is set.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess I'm not following. What exactly is the concern with losing the explicit NettyConnectorFactory setup? The only thing which can be set there is host and port. The URL provides the ability to set host and port as well as any other property.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What exactly is the concern with losing the explicit NettyConnectorFactory setup?

That's most probably the source of the confusion. When a URL is set, no specific transport is set. When a host and port are set a NettyConnectorFactory transport is set. Looking a bit more NettyConnectorFactory seems the default implementation anyway so we'd use that as well.

That wasn't clear hence why we asked explicitly.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When a URL is set, no specific transport is set.

That's not accurate. Which "transport" is used is determined by the URL's scheme.

There are only 2 ConnectorFactory implementations in Artemis - NettyConnectorFactory and InVMConnectorFactory. To use the NettyConnectorFactory you simply need to use the tcp:// scheme in the URL. To use the InVMConnectorFactory you need to use the vm:// scheme.

Copy link
Member

@snicoll snicoll Dec 21, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's not accurate.

Sorry, poor choice of words.

I meant that the auto-configuration doesn't do anything special when a broker url is set while it does something explicit (in code) when a host is set. We're very cautious to not introduce any inconsistency and the reason why I asked you here.

Thanks for the follow-up and the feedback !

Constructor<T> constructor = factoryClass.getConstructor(boolean.class, TransportConfiguration[].class);
connectionFactory = constructor.newInstance(false, new TransportConfiguration[] { transportConfiguration });
}
String user = this.properties.getUser();
if (StringUtils.hasText(user)) {
connectionFactory.setUser(user);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
*
* @author Eddú Meléndez
* @author Stephane Nicoll
* @author Justin Bertram
* @since 1.3.0
*/
@ConfigurationProperties(prefix = "spring.artemis")
Expand All @@ -44,14 +45,25 @@ public class ArtemisProperties {

/**
* Artemis broker host.
*
* This property is deprecated. Use <code>brokerUrl</code> instead.
*/
@Deprecated
private String host = "localhost";

/**
* Artemis broker port.
*
* This property is deprecated. Use <code>brokerUrl</code> instead.
*/
@Deprecated
private int port = 61616;

/**
* Artemis broker port.
*/
private String brokerUrl = "tcp://localhost:61616";

/**
* Login user of the broker.
*/
Expand Down Expand Up @@ -91,6 +103,14 @@ public void setPort(int port) {
this.port = port;
}

public String getBrokerUrl() {
return this.brokerUrl;
}

public void setBrokerUrl(String brokerUrl) {
this.brokerUrl = brokerUrl;
}

public String getUser() {
return this.user;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,15 @@ void nativeConnectionFactory() {
void nativeConnectionFactoryCustomHost() {
this.contextRunner.withUserConfiguration(EmptyConfiguration.class)
.withPropertyValues("spring.artemis.mode:native", "spring.artemis.host:192.168.1.144",
"spring.artemis.port:9876")
"spring.artemis.port:9876", "spring.artemis.broker-url: ")
.run((context) -> assertNettyConnectionFactory(
getActiveMQConnectionFactory(getConnectionFactory(context)), "192.168.1.144", 9876));
}

@Test
void nativeConnectionFactoryCustomUrl() {
this.contextRunner.withUserConfiguration(EmptyConfiguration.class)
.withPropertyValues("spring.artemis.mode:native", "spring.artemis.broker-url:tcp://192.168.1.144:9876")
.run((context) -> assertNettyConnectionFactory(
getActiveMQConnectionFactory(getConnectionFactory(context)), "192.168.1.144", 9876));
}
Expand Down Expand Up @@ -377,7 +385,11 @@ private TransportConfiguration assertNettyConnectionFactory(ActiveMQConnectionFa
TransportConfiguration transportConfig = getSingleTransportConfiguration(connectionFactory);
assertThat(transportConfig.getFactoryClassName()).isEqualTo(NettyConnectorFactory.class.getName());
assertThat(transportConfig.getParams().get("host")).isEqualTo(host);
assertThat(transportConfig.getParams().get("port")).isEqualTo(port);
Object transportConfigPort = transportConfig.getParams().get("port");
if (transportConfigPort instanceof String) {
transportConfigPort = Integer.parseInt((String) transportConfigPort);
}
assertThat(transportConfigPort).isEqualTo(port);
return transportConfig;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5709,25 +5709,24 @@ By default, ActiveMQ creates a destination if it does not yet exist so that dest


[[boot-features-artemis]]
==== Artemis Support
Spring Boot can auto-configure a `ConnectionFactory` when it detects that https://activemq.apache.org/components/artemis/[Artemis] is available on the classpath.
==== ActiveMQ Artemis Support
Spring Boot can auto-configure a `ConnectionFactory` when it detects that https://activemq.apache.org/components/artemis/[ActiveMQ Artemis] is available on the classpath.
If the broker is present, an embedded broker is automatically started and configured (unless the mode property has been explicitly set).
The supported modes are `embedded` (to make explicit that an embedded broker is required and that an error should occur if the broker is not available on the classpath) and `native` (to connect to a broker using the `netty` transport protocol).
When the latter is configured, Spring Boot configures a `ConnectionFactory` that connects to a broker running on the local machine with the default settings.

NOTE: If you use `spring-boot-starter-artemis`, the necessary dependencies to connect to an existing Artemis instance are provided, as well as the Spring infrastructure to integrate with JMS.
NOTE: If you use `spring-boot-starter-artemis`, the necessary dependencies to connect to an existing ActiveMQ Artemis instance are provided, as well as the Spring infrastructure to integrate with JMS.
Adding `org.apache.activemq:artemis-jms-server` to your application lets you use embedded mode.

Artemis configuration is controlled by external configuration properties in `+spring.artemis.*+`.
ActiveMQ Artemis configuration is controlled by external configuration properties in `+spring.artemis.*+`.
For example, you might declare the following section in `application.properties`:

[source,yaml,indent=0,configprops,configblocks]
----
spring:
artemis:
mode: native
host: "192.168.1.210"
port: 9876
broker-url: "tcp://192.168.1.210:9876"
user: "admin"
password: "secret"
----
Expand Down