ActiveMQ Artemis vs ActiveMQ "Classic" connection - spring-boot

Is there any difference between ActiveMQ Artemis connection configuration between aplication.yaml:
spring.artemis.mode=native
spring.artemis.host=192.168.1.210
spring.artemis.port=9876
vs
spring.activemq.broker-url=tcp://192.168.1.210:9876
spring.activemq.user=admin
spring.activemq.password=secret
If you use only this dependency:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-artemis</artifactId>
</dependency>
I assume that spring-boot-starter-artemis allows you to connect via JMS, and that is spring.activemq.XXX, and if you want to connect in the Artemis approach then you use spring.artemis.XXX the bean will autocofigure.
But I am not sure
I read the key differences on this page.
Which one is better? For JMS (ActiveMQConnectionFactory) I can use CachingConnectionFactory, is it needed for artemis auto-configuration?

If you're using spring-boot-starter-artemis that indicates you want to connect to an instance of ActiveMQ Artemis which means you'll want to configure spring.artemis.XXX properties. Assuming you're using spring-boot-starter-artemis 2.7.0 (i.e. the latest) you'll want to use spring.activemq.broker-url as referenced in the Spring documentation, e.g.:
spring.artemis.mode=native
spring.artemis.broker-url=tcp://192.168.1.210:9876
spring.artemis.user=admin
spring.artemis.password=secret
The host and port properties you referenced were deprecated in favor of broker-url awhile back.
The documentation continues:
By default, a CachingConnectionFactory wraps the native ConnectionFactory with sensible settings that you can control by external configuration properties in spring.jms.*:
spring.jms.cache.session-cache-size=5
If you’d rather use native pooling, you can do so by adding a dependency to org.messaginghub:pooled-jms and configuring the JmsPoolConnectionFactory accordingly, as shown in the following example:
spring.artemis.pool.enabled=true
spring.artemis.pool.max-connections=50
Whether you use spring-boot-starter-artemis with spring.artemis.XXX properties or spring-boot-starter-activemq with spring.activemq.XXX properties the underlying Spring components will use JMS to connect.

Related

Migrating to Spring Boot 3 with ActiveMQ "Classic"

I am trying to migrate to Spring Boot 3 with the new namespace jakarta.xx instead of javax.xx but the ActiveMQ "Classic" client has not been updated and was deprecated. Is there a way to continue using the old ActiveMQ client?
I tried the new ActiveMQ Artemis client but it seems like they are not interoperable with the ActiveMQ "Classic" server.
Including the old ActiveMQ client results in not being able to use JMSTemplate for configuration because JMSTemplate uses jakarta.xx and expects a ConnectionFactory from jakarta.xx not javax.xx
Edit: Didn't work so the only way is to upgrade to artemis. That way the codebase is also nearly unchanged.
As you noticed there is no ActiveMQ client that supports the Jakarta namespace JMS dependency or in fact none that supports JMS 2.0 so you really need to move to something else such as an ActiveMQ Artemis broker and the ActiveMQ Artemis client or Qpid JMS AMQP client v2.1.0 which both support JMS 2.0 and use the Jakarta APIs.
If you are dead set on sticking with ActiveMQ 5.x you can try using the Qpid JMS v2.1.0 client which does use the Jakarata JMS API but you will need to be somewhat careful as the 5.x broker doesn't support JMS 2.0 so some parts of the API can trigger unexpected behaviors. The AMQP support in the 5.x broker is not as fully integrated and JMS 2.0 aware as that of the Artemis broker so you can encounter issues you wouldn't see if you moved on to the Artemis broker.
Edit: Didn't work so the only way is to upgrade to artemis. That way the codebase is also nearly unchanged.
To continue to use ActiveMQ 5.x with Spring 3 and Jakarta EE 9, two updates are needed on the ActiveMQ 5.x side-- JMS 2.0 support, and then support for javax.jms -> jakarta.jms namespace change.
The first part is the biggest, and is underway. The ActiveMQ 5.x main branch has preview support for JMS 2.0, and there are plans to provide Jakarta namespace support shortly after.
This is a good page to track JMS 2.0 progress in ActiveMQ 5.x
ref: https://activemq.apache.org/jms2
UPDATE: A temporary, jakarta-based client suitable for transition activity is available: https://github.com/hyteio/activemq-client-jakarta
While waiting for ActiveMQ update to Jakarta EE 9 i removed
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-activemq</artifactId>
</dependency>
And included
<dependency>
<groupId>org.apache.activemq</groupId>
<artifactId>activemq-client</artifactId>
<version>5.17.3</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jms</artifactId>
<version>5.3.24</version>
</dependency>
It worked like a charm with Spring Boot 3.0.0

Spring Integration between two message brokers

I am new to Spring-Integration.
My use case is:
Listen to a RabbitMQ queue/topic, get the message, process it, send it to other message broker (mostly it will be another RabbitMQ instance).
Expected load: 5000 messages/sec
In application.properties we can set configurations for one host.
How to use Spring Integration between two message brokers?
All the examples that i see are for one message broker. Any pointers to get started with two message brokers and Spring Integration.
Regards,
Mahesh
Since you mention an application.properties it sounds like you use Spring Boot with its auto-configuration feature. It is very important detail in your question because Spring Boot has opinion about auto-configuration and you really can have only one broker connection configuration auto-configured. If you would like to have an another similar in the same application, then you should forget that auto-configuration feature. You still can use the mentioned application.properties, but you have to manage them manually.
Since you talk about a RabbitMQ connection, so you need to exclude RabbitAutoConfiguration and manage all the required beans manually:
#SpringBootApplication(exclude = RabbitAutoConfiguration.class)
You still can use the #EnableConfigurationProperties(RabbitProperties.class) on some your #Configuration class to be able to inject that RabbitProperties and populate respective CachingConnectionFactory. For the second broker you can introduce your own #ConfigurationProperties or just configure everything manually reading properties via #Value. See more info about manual connection factory configuration in Spring AMQP reference manual: https://docs.spring.io/spring-amqp/docs/2.2.1.RELEASE/reference/html/#connections

ActiveMQ rebalanceClusterClients not working with Spring Boot JMS

We are using the Spring JmsTemplate implementation with a CachingConnectionFactory. We have configured the connection with a failover-url:
failover:(ssl://172.16.0.11:61616,ssl://172.16.0.12:61616)?maxReconnectDelay=2000
On the transport connector in ActiveMQ we have enabled the option "rebalanceClusterClients":
<transportConnector name="openwire" uri="ssl://0.0.0.0:61616?maximumConnections=1000&wireFormat.maxFrameSize=104857600" rebalanceClusterClients="true">
<publishedAddressPolicy>
<publishedAddressPolicy publishedHostStrategy="IPADDRESS" />
</publishedAddressPolicy>
</transportConnector>
However, all of the clients are connecting to the first broker in the list of brokers instead of some of them being rebalanced to the second broker.
Previously we did not use the Spring JMS implementation, but instead we used the ActiveMQ libraries directly. This implementation did allow rebalancing the connected clients.
Is something in Spring preventing the rebalancing? Perhaps the CachingConnectionFactory?
EDIT 2019-07-10
I've found these two (p1 and p2) posts on SO where it is stated that CachingConnectionFactory doesn't play nicely with the failover-protocol. However, I think this has been resolved since then as we do see the connections moving between brokers if a broker is turned off.
What we do not see is connections being balanced across brokers. We did see this behavior when we were still using our own custom JMS implementation. So might it be something in Spring or the JmsTemplate?
The actual problem was not ActiveMQ or Spring rather an external firewall prevented this from working.

In Spring Boot, How do I declare that my JMS server is embedded?

The Spring Boot documentation has this very brief illustration of an embedded JMS server: "Two beans that you don’t see defined are JmsTemplate and ConnectionFactory. These are created automatically by Spring Boot. In this case, the ActiveMQ broker runs embedded." Huh? The Reference Documentation doesn't say a thing about it. I need to create two VMs, each running from its own jar file, and I need one of them to launch an embedded JMS server, but I have no idea how to do this. Can somebody point me in the right direction. (If you provide a link, I would prefer some clear documentation over an example, but I'll be happy with a good example.)
You are looking at the wrong reference documentation. Yours is from Spring Integration.
The one of Spring Boot can be found here:
https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#boot-features-activemq
And there you will find the answer:
When ActiveMQ is available on the classpath, Spring Boot can also
configure a ConnectionFactory. If the broker is present, an embedded
broker is automatically started and configured (provided no broker URL
is specified through configuration).

How to pool the JMS connection in a standalone Java application?

We are working on an IBM WebSphere MQ application, and we use JMS API to operate the message. But we have a problem that the connection takes too much time, and we want to pool the JMS connection, for it's a standalone application, we have no application container to provide JNDI or pooling service. So is there a solution to resolve this? For JDBC we can use DBCP or c3p0 to archive pooling datasource, in JMS, is there any similar project that can pool JMS connections?
It used to be that the JMS MQConnectionFactory had pooling built in, but it seems that in version 7, it has been removed.
Set the use of ConnectionPooling in earlier versions of the WebSphere
MQ classes for JMS. This method is retained for compatibility with
older MQJMS applications, but, because this Connection Pooling
functionality has been removed from version 7, setting this property
will have no effect.
In the absence of anything else, you can use Apache Commons Pool. Same idea as DBCP (which uses Pool) but for non JDBC objects.
Spring's CachingConnectionFactory works well for this use case.
This answer in https://stackoverflow.com/a/31119435/1765341 explains how to do this in Tomcat, but the code there can easily be adapted for Java standalone applications. This should be much easier (and less error prone) than writing an Apache Commons Pool implementation.

Resources