Spring config client not able to get values from config server - java

I am trying to read a message from different properties based on the profile. For example I have placed 3 properties files in github:
test-app-dev.properties
test-app-prod.properties
test-app-stage.properties
Now my config server has below details in application.properties
spring.cloud.config.server.git.uri=https://github.com/asudheer09/local-config-server-configs.git
server.port=8888
spring.cloud.config.server.git.default-label=main
spring.application.name=config-server
server.servlet.context-path=/config-service
When I am trying to access the http://localhost:8888/config-service/test-app-prod.properties I can see the properties file on browser and similarly others also i can see.
The below are my config client details:
In bootstrap.properties:
spring.profiles.active=dev
spring.cloud.config.uri=http://localhost:8888/config-service
management.security.enabled=false
spring.application.name=test-app
java file :
package com.example.demo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.core.env.Environment;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
#SpringBootApplication
#RefreshScope
public class SpringProfilesExampleApplication {
#Autowired
public void setEnv(Environment e) {
System.out.println(e.getActiveProfiles().toString());
System.out.println(e.getProperty("message"));
}
public static void main(String[] args) {
SpringApplication.run(SpringProfilesExampleApplication.class, args);
}
}
#RefreshScope
#RestController
class MessageRestController {
#Value("${message:Config Server is not working. Please check...}")
private String msg;
#GetMapping("/msg")
public String getMsg() {
return this.msg;
}
}
When i run my config client i am getting the message value as null, but i am not able to see any error message. can any one help me on this ?

Try making the following changes
In git you must have different urls for each enviroment (dev, prod, ..).
spring:
cloud:
config:
server:
git:
repos:
dev:
pattern: test-app/dev
uri: https://github.com/asudheer09/local-config-server-configs/test-app-dev.properties
prod:
pattern: test-app/prod
uri: https://github.com/asudheer09/local-config-server-configs/test-app-prod.properties
With these configurations your config server will serve clients using the following logic
If client application has name test-app and profile dev then it will load the properties from https://github.com/asudheer09/local-config-server-configs/test-app-dev.properties
If client application has name test-app and profile prod then it will load the properties from https://github.com/asudheer09/local-config-server-configs/test-app-prod.properties
It does not make any sense to try and make System.out.println directly on config server when it starts up. You don't need the application properties of config server but those properties that will be served on clients.
Check more info here
spring cloud config documentation

Related

Can't consume from ActiveMQ with Spring Boot Web

I am having trouble getting messages from a locally run ActiveMQ. I can produce them onto the queue and my PC also is registered as producer. However, another Spring App on the machine should be configured as a listener. So far it is not working. ActiveMQ is listening on the default ports.
My JMS config for the sender:
package at.dkepr.queueservice;
import org.apache.activemq.command.ActiveMQQueue;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import javax.jms.Queue;
#Configuration
public class JmsConfig {
#Bean
public Queue queue(){
return new ActiveMQQueue("indexing-queue");
}
}
And this is the consumer:
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.jms.annotation.EnableJms;
import org.springframework.jms.annotation.JmsListener;
import org.springframework.stereotype.Component;
import at.dkepr.entity.UserSearchEntity;
#Component
#EnableJms
public class JmsConsumer {
private final Logger logger = LoggerFactory.getLogger(JmsConsumer.class);
#JmsListener(destination = "indexing-queue", containerFactory = "jmsListenerContainerFactory")
public void receive(UserSearchEntity user){
logger.info(user.getEmail());
}
}
In the application.propertiers I have added the necessary properties:
spring.activemq.broker-url=tcp://localhost:61616
spring.activemq.user=admin
spring.activemq.password=admin
Also the UserSearchEntity implements Serializable.
To the best of my knowledge for this setup I should not even need a config for the consumer. Never the less, I added one.
import org.apache.activemq.ActiveMQConnectionFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jms.annotation.EnableJms;
import org.springframework.jms.config.DefaultJmsListenerContainerFactory;
#Configuration
#EnableJms
public class ConsumerConfig {
#Value("${spring.activemq.broker-url}")
private String brokerUrl;
#Bean
public ActiveMQConnectionFactory activeMQConnectionFactory() {
ActiveMQConnectionFactory activeMQConnectionFactory = new ActiveMQConnectionFactory();
activeMQConnectionFactory.setBrokerURL(brokerUrl);
return activeMQConnectionFactory;
}
#Bean
public DefaultJmsListenerContainerFactory jmsListenerContainerFactory() {
DefaultJmsListenerContainerFactory factory = new DefaultJmsListenerContainerFactory();
factory.setConnectionFactory(activeMQConnectionFactory());
factory.setConcurrency("1-3");
return factory;
}
}
I am not getting any error logs. Unfortunately, it is simply doing nothing.
This is a screenshot from the ActiveMQ web console with the enqueued messages:
My consuming application was running when I took this screenshot, but the broker clearly does not recognize it since the "Number of Consumers" is 0.
Edit:
I just tried adding the Listener to the same Spring Application where the Producer is. Surprinsingly, the Listener connected fine. It seems like the problem lies in the different Spring Applications. However, i used the same application.properties for both Spring Apps. The Config File is the same too.
To everyone having the same problem:
For me it was a simple problem with folder structure. For some reason the Application.java for the consumer service was in a subfolder. After i moved the Application.java one folder up, the connection to the ActiveMQ worked.

Issue executing Zuul proxy in Spring (bean type not found)

Spring Boot Starter : 2.1.4.RELEASE
i am trying to use spring-cloud-starter-netflix-zuul to setup service proxy in spring boot, however the jar throws the below exception during startup
***************************
APPLICATION FAILED TO START
***************************
Description:
Field server in org.springframework.cloud.netflix.zuul.ZuulServerAutoConfiguration required a bean of type 'org.springframework.boot.autoconfigure.web.ServerProperties' that could not be found.
The injection point has the following annotations:
- #org.springframework.beans.factory.annotation.Autowired(required=false)
Action:
Consider defining a bean of type 'org.springframework.boot.autoconfigure.web.ServerProperties' in your configuration.
Below is my Main
package com.xxx.serviceproxy;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.cloud.netflix.zuul.EnableZuulProxy;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.boot.WebApplicationType;
import org.springframework.boot.autoconfigure.web.ServerProperties;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Controller;
#Configuration
#ComponentScan
#EnableAutoConfiguration
#Controller
#EnableZuulProxy
#SpringBootApplication
public class ServiceProxyApplication {
public static void main(String[] args) {
new SpringApplicationBuilder(ServiceProxyApplication.class).web(WebApplicationType.NONE).run(args);
}
}
This happens because you are putting the annotation #EnableAutoConfiguration.
This annotation causes the class ZuulServerAutoConfiguration to be searched for.
You can see here:
https://github.com/spring-cloud/spring-cloud-netflix/blob/master/spring-cloud-netflix-zuul/src/main/java/org/springframework/cloud/netflix/zuul/ZuulServerAutoConfiguration.java
which has an autowired from
#Autowired
protected ServerProperties server;
And in the header of the class you can see the comments:
// Make sure to get the ServerProperties from the same place as a normal web app would
// FIXME #Import(ServerPropertiesAutoConfiguration.class)
public class ZuulServerAutoConfiguration {
which means it's not auto-configuring.
If you remove the annotation #EnableAutoConfiguration, it will no longer look for zuul autoconfiguration and you can configure zuul paths and other features in your application.yml (or application.properties), example:
zuul:
routes:
users:
path: /myusers/**
serviceId: users_service
Here the documentation to configure zuul:
https://cloud.spring.io/spring-cloud-netflix/multi/multi__router_and_filter_zuul.html

Setting "spring.config.name" property programmatically does not work

According to this blog post from December 2017, it is possible to change the name used to search for Spring Boot configuration files programmatically like this:
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
#SpringBootApplication
public class Application {
public static void main(String[] args) {
new SpringApplicationBuilder(Application.class)
.properties("spring.config.name:conf")
.build()
.run(args);
}
}
I have tried this using Spring Boot version 1.5.9-RELEASE, but this does not work. Setting spring.config.name as an argument does work:
mvn spring-boot:run -Dspring.config.name=conf
However, I do not have control over the arguments passed to my Spring Boot application when it is started so this is not an option.
Is it no longer possible to set spring.config.name programmatically, am I missing something, or is this a bug?
Doesn't directly answer the question, but I eventually discovered a workaround. Setting the spring.config.name by adding it to the arguments does work:
package com.ups.cep;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
#SpringBootApplication
public class Application {
public static void main(String[] args) {
List<String> arguments = new ArrayList<>(Arrays.asList(args));
arguments.add("-Dspring.config.name=conf");
SpringApplication.run(Application.class, arguments.toArray(new String[arguments.size()]));
}
}
Your example works for me (Spring Boot 2.4.3) so it could be bug at that time.
A similar SO answer also uses SpringApplicationBuilder.properties(String... defaultProperties) to define configuration name.
new SpringApplicationBuilder(Application.class)
.properties("spring.config.name:conf")
.build()
.run(args);
I checked both spring.config.name=conf and spring.config.name:conf and they work.

Camel read properties file

How do I configure the use of a properties file using Java DSL and the Main object?
According to this page I should be able to call something like:
main.setPropertyPlaceholderLocations("example.properties");
However that simply doesn't work. It seems that option wasn't added until Camel 2.18 and I'm running 2.17.1.
What was the original way to set a properties file to use when letting the application run in a standalone form?
Some backstory:
I'm trying to convert from Spring to Java DSL. During that conversion I was attempting to have my Camel application run on its own. I know that is achieved using main.run();.
I had things "functioning" when using the CamelContext, but that cannot run on its own. So I know using the following will work in that case:
PropertiesComponent pc = new PropertiesComponent();
pc.setLocation("classpath:/myProperties.properties");
context.addComponent("properties", pc);
Is there some way I can tell the main to use that setup? Or is there something else needed?
You can use the following snippet:
PropertiesComponent pc = new PropertiesComponent();
pc.setLocation("classpath:/myProperties.properties");
main.getCamelContexts().get(0).addComponent("properties", pc);
Also, if you are using camel-spring, you could use org.apache.camel.spring.Main class, it should use the property placeholder from your application context.
Since you are mentioning you are in the process to move from Spring XML to Java Config here's a minimum application that is using properties and injecting it into a Camel route (it's really properties management in Spring injected into our Camel route bean):
my.properties:
something=hey!
Main class:
package camelspringjavaconfig;
import org.apache.camel.spring.javaconfig.CamelConfiguration;
import org.apache.camel.spring.javaconfig.Main;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
#Configuration
#ComponentScan("camelspringjavaconfig")
#PropertySource("classpath:my.properties")
public class MyApplication extends CamelConfiguration {
public static void main(String... args) throws Exception {
Main main = new Main();
main.setConfigClass(MyApplication.class); // <-- passing to the Camel Main the class serving as our #Configuration context
main.run(); // <-- never teminates
}
}
MyRoute class:
package camelspringjavaconfig;
import org.apache.camel.builder.RouteBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Component;
#Component
public class MyRoute extends RouteBuilder {
#Autowired
Environment env; //<-- we are wiring the Spring Env
#Override
public void configure() throws Exception {
System.out.println(env.getProperty("something")); //<-- so that we can extract our property
from("file://target/inbox")
.to("file://target/outbox");
}
}

Do annotations on a class still get called when only accessing static members?

I have the following class:
package hello;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.SpringApplication;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.stereotype.Component;
#Component
#EnableAutoConfiguration
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
If I reference it in my main camel route, like so:
package com.example.integration;
import hello.*;
import org.apache.camel.ProducerTemplate;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class TestCamelSpring {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("camelspring.xml");
ProducerTemplate camelTemplate = context.getBean("camelTemplate", ProducerTemplate.class);
Application.main(args);
System.out.println("Message Sending started");
camelTemplate.sendBody("jms:queue:testQSource","Sample Message");
System.out.println("Message sent");
}
}
Do my annotations in Application.class still get accessed even though I only reference Application.main?
I ask because the #EnableAutoConfiguration is supposed to configure the application for Tomcat, but now that I am not running Application.class directly, the application is defaulting to jetty and then I get an error that WebSockets are only supported in Tomcat.
Has anyone had this issue before or know how to solve it?
Here is the stack trace. I can see from the console log that it never starts the Tomcat instance that it does when the whole class is accessed in the example. It seems to be continuing as if it is a jetty app rather than Tomcat. Please correct me if any of these assumptions are wrong:
Caused by: java.lang.IllegalStateException: Websockets are currently only supported in Tomcat (found class org.springframework.boot.context.embedded.jetty.JettyEmbeddedServletContainerFactory).
at org.springframework.boot.autoconfigure.websocket.WebSocketAutoConfiguration$1.customize(WebSocketAutoConfiguration.java:74)
at org.springframework.boot.context.embedded.EmbeddedServletContainerCustomizerBeanPostProcessor.postProcessBeforeInitialization(EmbeddedServletContainerCustomizerBeanPostProcessor.java:67)
at org.springframework.boot.context.embedded.EmbeddedServletContainerCustomizerBeanPostProcessor.postProcessBeforeInitialization(EmbeddedServletContainerCustomizerBeanPostProcessor.java:54)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyBeanPostProcessorsBeforeInitialization(AbstractAutowireCapableBeanFactory.java:407)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1545)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:539)
... 16 more
First of all, annotations cannot be "called".
Annotations are data, not code. In your case Spring Boot reads your annotations when you call SpringApplication.run(Application.class, args); and performs necessary configurations, therefore it doesn't matter how you call Application.main().
I guess your problem is caused by the fact that you have Jetty in the classpath, and it forces Spring Boot to use Jetty rather than Tomcat as embedded servlet container.
So, try to do the following:
Find out how Jetty appeared in your classpath
Use mvn dependency:tree -Dverbose if you use Maven
If you don't need Jetty in the classpath, exclude it from dependencies
Otherwise, you need to force Spring Boot to ignore presence of Jetty
Something like exclude = EmbeddedServletContainerAutoConfiguration.EmbeddedJetty.class in #EnableAutoConfiguration may help

Categories