Passing environment values in application.properties - spring-boot

I am new to spring-boot and trying to pass the Backend credentials as environment values into my application.properties.
To set the Environment values in Tomcat and created a setenv.bat and setenv.sh
Location: \apache-tomcat-7.0.53-windows-x64\apache-tomcat-7.0.53\bin
set username="ABC"
set password="xyz"
These Environment values are getting set and i am able to print it also using
#Autowired
private Environment env;
String userName = env.getProperty("username");
String pwd = env.getProperty("password");
and trying to access these values in application.properties like
spring.datasource.username=${username}
spring.datasource.password=${password}
but that is not working.
I tried the different way and mentioned the environment variables name in setEnv.bat like
set spring.datasource.username="ABC"
set spring.datasource.password="xyz"
i was hoping that Spring Boot will read these values from Env and pass it to data source so that i do not have to mention explicitly in application.properties but that is also not working. please note, i do not have any bean.xml file and i am doing pure annotation based development. Any inputs here..

If I understand correctly, then you want to access the variables written in your application.properties file
This can be done in many ways, but one simple way is to do following in your .java file :
#PropertySource("classpath:application.properties")
class AppConfig {
#Bean
public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
return new PropertySourcesPlaceholderConfigurer();
}
}
#Test
public void test_fetch_property() {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
context.registerShutdownHook();
Environment environment = context.getBean(Environment.class);
String strWhoami = environment.getProperty("whoami.name").toString();
assertThat(strWhoami,equalTo("\"John Doe\""));
}
The whoami.name is the property that is fetched from application.properties file and tested
application.properties file:
#----------------------------------------------------------
# Show your self
#----------------------------------------------------------
whoami.name="John Doe"
I hope that this can help a bit

Related

spring set Profile from external properties file

I am setting my database properties from an external file and am trying to do the same for the active profile, but am not having any luck.
In app.properties if tried: spring.config.location= C:\\run\\secrets\\test but that did not work.
In the same config file that I have the database properties being read in I've tried:
#Component
#Configuration
#PropertySource(value={"file:/run/secrets/file.properties"}, ignoreResourceNotFound = true)
public class AppProperties {
#Resource
private Environment env;
#Bean
public Properties props(){
Properties props = new Properties();
props.setProperty("spring.profiles.default", env.getRequiredProperty("spring.profiles.active"));
//props.put("spring.profiles.active", env.getRequiredProperty("spring.profiles.active"));
return props;
}
}
In my external file I've tried both
spring.profiles.active=dev and spring.profiles.default=dev
Nothing seems to work.
If I understand correctly, your file is on Disk C.
So, in windows, the external file path should be like this:
#PropertySource(value={"file:///C:/run/secrets/file.properties"}, ignoreResourceNotFound = true)

Active profile in SpringBootTest based on system variable

As the host of Redis is different in local and CI, my #Tests can pass locally, they can't pass in CI.
Firstly, I tried to mock the RedisTemplate like this:
RedisTemplate redisTemplate = mock(RedisTemplate.class);
ValueOperations valueOperations = mock(ValueOperations.class);
when(redisTemplate.opsForValue()).thenReturn(valueOperations);
when(valueOperations.increment(anyString(), anyLong())).thenReturn(1L);
when(valueOperations.get("a#a.com")).thenReturn("1");
It did mocked RedisTemplate, but can't mock redisTemplate.opsForValue() and valueOperations.increment(...) ( I can't find reason )
Then, I wrote two profiles named application-ci-test.yml and applicaiton-test.yml, tried to active one of them based on system environment variable
I learnd from here that I can set active profile in this way:
#Configuration
public class MyWebApplicationInitializer
implements WebApplicationInitializer {
#Override
public void onStartup(ServletContext servletContext) throws ServletException {
servletContext.setInitParameter(
"spring.profiles.active", "dev");
}
}
and this way:
#Autowired
private ConfigurableEnvironment env;
...
env.setActiveProfiles("someProfile");
But I don't know how to use them. The system variable can get by System.getenv(..). So now I want to know how to active profile based on the variable I get.
I found a way to active corresponding profile based on system variable or property:
import org.springframework.test.context.ActiveProfilesResolver;
public class SpringActiveProfileResolver implements ActiveProfilesResolver {
#Override
public String[] resolve(Class<?> testClass) {
final String isCITest = System.getEnv("isCITest");
return new String[] { isCITest == null ? "test" : "ci-test" };
}
}
then use the parameter resolver in #ActiveProiles:
#ActiveProfiles(resolver = SpringActiveProfileResolver.class)
How to set environment variable is anther issue, and answers above have already answered it
Assuming your #Test methods are in a class with the #SpringBootTest annotation, you can use #ActiveProfiles to set the profile.
#SpringBootTest
#ActiveProfiles("someProfile")
Use run parameters inside your CI job/script.
Depending how You start Your tests, You can for example do it with VM arguments
mvn test -Dspring.profiles.active=ci-test
or
java -jar -Dspring.profiles.active=ci-test
or whatever.
On the other hand you can use program arguments:
java -jar --spring.profiles.active=ci-test
One way or the other, providing active profile at start will activate property file of your choice.
If you want some specific piece of code (configuration class for example) to be run with specific profile only, annotate that piece of code with #Profile("ci-test")
Example:
#Configuration
#Profile("ci-test")
public class SomeConfiguration {
//any configuration beans etc.
}
Following class will only be loaded when Your active profile will be "ci-test". So if You run Your app on Your CI server with one of the commands above, both property file named "ci-test" and this configuration class will get loaded.
It's also worth adding that in order for some code to run in ALL profiles EXCEPT specified, you can negate the name inside profile annotation like: #Profile("!ci-test").
Code annotated like that will run with all profiles (including default) except "ci-test".

application.properties spring boot value injection

I'm working on the REST API with spring boot. I want to use git in my project. in the file application.properties I have the database Url, username and password that I do not want to push on git. I don't know how can I create a file which contains my database configuration and how to inject those configurations in the application.properties .
application.properties
## Server Properties
server.port= 5000
## Spring DATASOURCE (DataSourceAutoConfiguration & DataSourceProperties)
spring.datasource.url= jdbc:mysql://localhost:3306/MyApp?useSSL=false&serverTimezone=UTC&useLegacyDatetimeCode=false
spring.datasource.username= user
spring.datasource.password= pass
Spring picks up configuration properties not only from the application.properties but also from command line arguments, JAVA System-properties or from environmental-variables.
See complete list here: Spring Externalized Configuration.
So - for reference - you can keep the properties in the application.properties file with some default values (like in your example) in order to let other users know what kind of properties they can set for your application.
But instead of setting your real values there, you can either pass the variable to your application as arguments, like
-Dspring.datasource.username=user -Dspring.datasource.password= pass
or you can set them as environmental variables.
You can even create multiple configuration with different settings. If Spring cannot find a variable in the current configuration, then it will pick it up from application.properties (or from the other sources - see above)
first you should add application.properties to .ignore file like this
application.properties
if you will just connect to database you won't need to inject values by hand you just write it in application.properties
but if you want to put values in properties file and use it in Application
package com.microservice.test.limitservice;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
#Component
#ConfigurationProperties("limit-service")
public class Configuration {
private int minimum;
private int maximum;
public int getMinimum() {
return minimum;
}
public void setMinimum(int minimum) {
this.minimum = minimum;
}
public int getMaximum() {
return maximum;
}
public void setMaximum(int maximum) {
this.maximum = maximum;
}
}
and how to inject it simply
#Autowired
private Configuration configuration;
the application.properties file could be like this
limit-service.minimum=56333445
limit-service.maximum=6500
you should notice that it start with as example limit-service
and #ConfigurationProperties("**limit-service**")
And if you want to store your configuration in application.properties secure
you can see this link Spring Boot how to hide passwords in properties file

How to access a Spring Boot Application's name programmatically?

I've defined an application name using the bootstrap.yml file in my spring boot application.
spring:
application:
name: abc
How can i get this application name during runtime/programmatically ?
You should be able to use the #Value annotation to access any property you set in a properties/YAML file:
#Value("${spring.application.name}")
private String appName;
#Autowired
private ApplicationContext applicationContext;
...
this.applicationContext.getId();
Please, find this:
# IDENTITY (ContextIdApplicationContextInitializer)
spring.application.name=
spring.application.index=
In Spring Boot Reference Manual.
And follow with source code for that ContextIdApplicationContextInitializer class:
#Override
public void initialize(ConfigurableApplicationContext applicationContext) {
applicationContext.setId(getApplicationId(applicationContext.getEnvironment()));
}
Where the default behavior is with this:
/**
* Placeholder pattern to resolve for application name
*/
private static final String NAME_PATTERN = "${vcap.application.name:${spring.application.name:${spring.config.name:application}}}";
Since the #Value annotation is discouraged in Spring Boot when referencing configuration properties, and because applicationContext.getId(); doesn't always return the value of spring.application.name another way is to get the value from the Environment directly
private final Environment environment;
...
public MyBean(final Environment environment) {
this.environment = environment;
}
...
private getApplicationName() {
return this.environment.get("spring.application.name");
}
Another possible way would be to create your own ConfigurationProperties class to get access to the value.
I'm not saying these are the best ways, and I hope/wish that there is a better way, but it is a way.
Note! If your using a SpringBootTest, you need to suplly the properties/yml.
Otherwise, the environment/appcontext does not load the config files.
The, your app name is not set.
Like so:
#PropertySource("classpath:application.properties")
#RunWith(SpringRunner.class)
#SpringBootTest
....
This post is aged but I hate unanswered questions.
So use the following snippet:
#Value("${spring.application.name [: defaultValue]}")
private String appName;
What is between [] is optional.
So I found a really ugly way to do this, but it works so I'm not searching further. Maybe this will help someone.
The basic premise is that spring Environment stores the value inside a propertySource.. It appears that bootstrap config is stored in the ResourcePropertySource and so you can get it from that. For me it is currently throwing an exception, but then I can get the value out of the exception, so I haven't looked any further:
try {
this.environment.getProperty("name", ResourcePropertySource.class);
} catch (ConversionFailedException e) {
String res = (String)e.getValue();
}
And then you can just do this for every property you are interested in.
Like I said ugly, but it works.

creating custom PropertySourcesPlaceholderConfigurer using property loaded dynamically

I am facing some challenge creating PropertySourcesPlaceholderConfigurer based on some value that is available in another property file.
I have a property file, custom-{environment}.property, which contains a value, that is needed to set location of PropertySourcesPlaceholderConfigurer.
My CustomConfiguration looks something like:
#Bean
public static PropertySourcesPlaceholderConfigurer placeholderConfigurer() {
PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer = new PropertySourcesPlaceholderConfigurer();
propertySourcesPlaceholderConfigurer.setLocation(customLocation);
//Custom url location based on a String available in the properties file. This is the problem area
return propertySourcesPlaceholderConfigurer;
}
I want to populate this customLocation from the properties file. Tried autowiring Environment, but it's failing as environment is null when placeholderConfigurer() is getting called. Tried using #PropertySource("custom-${environment}.property") and then #Value("**customLocation**"), but that's also not working.
Please let me know how this can be done. Thanks in advance.
I would suggest adding an ApplicationContextInitializer to load your property files instead of a plain #PropertySource. First load your custom-{environment}.properties next your configurable properties file.
public class PropertySourceInitializer implements ApplicationContextInitializer {
private static final String DEFAULT_CONFIG_FILE = "classpath:custom-${environment}.properties";
#Override
public void initialize(ConfigurableApplicationContext applicationContext) {
final ConfigurableEnvironment env = applicationContext.getEnvironment();
final MutablePropertySources mps = env.getPropertySources();
//
Resource resource = applicationContext.getResource(env.resolvePlaceholders(DEFAULT_CONFIG_FILE));
mps.addLast(new ResourcePropertySource(resource.getDescription(), resource));
String additional = env.getProperty("name.of.property");
if (StringUtils.hasText(additional) {
Resource additionalResource = applicationContext.getResource(env.resolvePlaceholders(additional));
if (additionalResource.isReadable() ) {
mps.addLast(new ResourcePropertySource(resource.getDescription(), resource));
}
}
}
}
Trying to get it to work with a #PropertySource will be much harder as the phases in which the PropertySourcesPlaceHolderConfigurer is created is different then the one in which the #PropertySource annotations are scanned. Staged loading of #PropertySource (which is basically what you want) is quite difficult. Spring Boot also has its own loading mechanism (which actually is also a ApplicationContextInitializer.
Can you try setting your location as a system property?
#Value("#{ systemProperties['myapp.location'] }")
private String location;
You need to set "myapp.location" as system property.

Resources