spring #JmsListener non compile time replacement - spring

Looking for some alternative JMS destination configuration. The most common way of configuring destination and listener is by using annotation.
#JmsListener(destination = destination)
public void fetchMessage(final Message message) {
However, destination property have to be provided during the compile time. How to quickly replace it using some property which will be resolved only during runtime?

You can use a property placeholder for the destination
#JmsListener(destination = "${queue.name}")
Then set the property in some property source available to the application (e.g. application.properties or application.yml for a boot app, or a system property -Dqueue.name=foo for any app).

Related

Embedded Kafka Broker IP Not Resolving in Property File

I'm facing an issue where my Kafka ProducerConfig is getting an invalid bootstrap.servers value because my unit test #PropertySource isn't resolving the spring.embedded.kafka.brokers property. When I dump my producer config to the logs, I get the following:
acks = 0
batch.size = 10000
bootstrap.servers = [${spring.embedded.kafka.brokers}]
...
Clearly, the property isn't getting resolved. Suppose I have the following embedded Kafka test.
#EmbeddedKafka
#SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.NONE)
#RunWith(SpringRunner.class)
public class EmbeddedKafkaTest {
#Value("${spring.embedded.kafka.brokers}")
private String embeddedKafkaBrokers;
#Test
public void test(){}
#SpringBootConfiguration
#PropertySource("classpath:kafkaTestProps.properties")
#EnableAutoConfiguration
class EmbeddedKafkaTestConfiguration {
}
}
and my kafkaTestProperties.properties file is as follows:
embedded-kafka-brokers=${spring.embedded.kafka.brokers}
...
embedded-kafka-brokers will eventually be provided to Kafka's ProducerConfig through some underlying autoconfiguration.
Interestingly, the embeddedKafkaBrokers instance field in the test class does contain the broker IPs set by embedded kafka.
I've concluded there's an issue with the property source loading order, where #EmbeddedKafka isn't setting the broker IP system property in time for kafkaTestProperties.properties to resolve it. This problem arose after porting our code base to Spring Boot 2 and Spring Cloud Finchley SR2, where Spring Kafka APIs have upgraded.
I've tried removing #SpringBootTest and wrapping the test() code in a SpringApplicationBuilder to no avail.
Any advice as to how I can fix this? Perhaps I can leverage #AutoConfigurationAfter or #Order? Is there a way to order the loading of property sources?
It looks that your placeholder is not valid.
Try to replace:
embedded-kafka-brokers=${"spring.embedded.kafka.brokers"}
with:
embedded-kafka-brokers=${spring.embedded.kafka.brokers}
and provide it to the producer using class with #ConfigurationProperties or using #Value("${embedded-kafka-brokers}").
documentation link

I want disable automatically delete JMS queue in spring boot application

Auto deletion of queues should be turned off,
1)If set "ems_value=true" in application.property file
#ConditionalOnProperty(name = "ems_value")
public class JmsConfiguration {
// Here get JMS connection
In this case what are mentioned queue names in application property file Its created by spring.
2)If set "ems_value=false" in application.property file
Queues deleted by spring class.
How can i disable or stop to delete queues.
It will only work on startup anyway, but you can always use 2 different beans that will do required job for you. Have once component with
#ConditionalOnProperty(name = "ems_value", havingValue="true")
that will do whatever you require, and have another component with
#ConditionalOnProperty(name = "ems_value", havingValue="false")
that will do cleanup operations only.

Refresh springboot configuration dynamically

Is there any way to refresh springboot configuration as soon as we change .properties file?
I came across spring-cloud-config and many articles/blogs suggested to use this for a distributed environment. I have many deployments of my springboot application but they are not related or dependent on one another. I also looked at few solutions where they suggested providing rest endpoints to refresh configs manually without restarting application. But I want to refresh configuration dynamically whenever I change .properties file without manual intervention.
Any guide/suggestion is much appreciated.
Can you just use the Spring Cloud Config "Server" and have it signal to your Spring Cloud client that the properties file changed. See this example:
https://spring.io/guides/gs/centralized-configuration/
Under the covers, it is doing a poll of the underlying resource and then broadcasts it to your client:
#Scheduled(fixedRateString = "${spring.cloud.config.server.monitor.fixedDelay:5000}")
public void poll() {
for (File file : filesFromEvents()) {
this.endpoint.notifyByPath(new HttpHeaders(), Collections
.<String, Object>singletonMap("path", file.getAbsolutePath()));
}
}
If you don't want to use the config server, in your own code, you could use a similar scheduled annotation and monitor your properties file:
#Component
public class MyRefresher {
#Autowired
private ContextRefresher contextRefresher;
#Scheduled(fixedDelay=5000)
public void myRefresher() {
// Code here could potentially look at the properties file
// to see if it changed, and conditionally call the next line...
contextRefresher.refresh();
}
}

Spring boot Artemis embedded broker behaviour

Morning all,
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 instanciate 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 artemis server on my machine.
Unfortunatelly, 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.
Thank you for tour help
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");
}
};
}
}
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 class where an InVMAcceptorFactory will be set for the configuration. You can edit this bean and change 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()));
}
}
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
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.

Does DeltaSpike ConfigResolver pick up runtime chnages

So I'm looking for CDI property injection and I'm looking at DeltaSpike
http://deltaspike.apache.org/configuration.html
I need to listen to property changes at runtime.
So, if I inject a property like so and then at runtime change the poll interval value in the properties file will this change get picked up?
#Inject
#ConfigProperty(name = "endpoint.poll.interval")
private Integer pollInterval;
It will depend on the scope of your config source. If your config source is RequestScoped, it's going to get refreshed with each request.

Resources