Why Spring Boot giving me wrong property value when i use this code
#Component
public class MyComponent implements ApplicationListener<ContextRefreshedEvent> {
#Value("${userName}")
private String user;
#Override
public void onApplicationEvent(ContextRefreshedEvent event) {
System.out.println("===================: "+user);
}
}
application.properties
userName=admin
It is not printing 'admin', it is printing my windows user name.
From Spring boot documentation :
Spring Boot uses a very particular PropertySource order that is designed to allow sensible overriding of values. Properties are considered in the following order:
1- Devtools global settings properties on your home directory (~/.spring-boot-devtools.properties when devtools is active).
[...]
10- OS environment variables.
[...]
14- Application properties outside of your packaged jar (application.properties and YAML variants).
As you can see, your OS env variable take precedence over variables defined in application.properties which is very useful when you want to override them.
You should consider renaming your variable so that it does not conflicts with windows' environment variable names.
Related
I want to set both property file (myproperty.properties) and log file location (myLogFile.log) through my own environment variable name (MYENV for example).
property file name must be different from spring boot application.properties name and log file has its own name also.
Do not want to use spring.config.name and spring.config.location.
MYENV will be set to "/locationFiles" value for example. myproperty.properties file location is "/locationFiles/config"
and myLogFile.log file location is "/locationFiles/log".
I know that I can use the following code snippet for reading my environment variable.
But How do I use propertiesLocation below to read the properties data in a simple Spring boot way?
I do not know how to define a corresponding java configuration class as It seems that configuration ppties file path cannot be set in a variable.
import org.springframework.core.env.Environment;
public class MyClass {
#Autowired
private Environment env;
String propertiesLocation;
private void propertyLocation() {
this.propertiesLocation = env.getProperty("MYENV")+"/config/";
}
}
The following code snippet does not match with what I want to do as I cannot
write something like that : #PropertySource(env.getProperty("MYENV")+"/config/")
#SpringBootApplication
#PropertySource("classpath:myproperty.properties")
public class MyApplication {
public static void main(String[] args) {
SpringApplication.run(MyApplication.class, args);
}
}
I saw Environment Specific application.properties file in Spring Boot application but I does not match exactly with what I've described above.
As I want to define my own environment variable name and file names.
And I'm also looking for another way than using java -jar -Dspring.config.location=<path-to-file> myBootProject.jar as defined in Spring boot how to read properties file outside jar.
I want to know if there is an alternative way to this method.
Consider a simple example as follows:
I have a hierarchy of Pets as follows:
public interface PetService{ .... }
// Now this service is implemented by DogPetService and CatPerService as follows:
#Service
#Profile("cat")
public class CatPetService implements PetService { ... }
#Profile({"dog", "default"})
#Service
public class DogPetService implements PetService { ... }
As seen in the example, the dog profile is the default.
Now, I have another hierarchy as follows (in the same project). Note: This is something I am trying to learn and have no relevance to real world project.
public interface GreetingService { ... }
// The Greeting service is implemented by two classes as follows:
#Profile({"EN", "default"} )
#Service
public class I18NEnglishGreetingService implements GreetingService { ... }
#Profile("ES")
#Service
public class I18NSpanishGreetingService implements GreetingService { ... }
As seen, for the GreetingService - I18NEnglishGreetingService is the default Profile
Now, I have application.properties in which I am setting the active profiles as follows:
spring.profiles.active=ES
When I run the application, spring boot fails to start as it fails to find bean implementation for the PetService.
Why doesn't it fall back for the DogPetService which is the default profile?
In the application.properties if I add dog/cat, then it works fine.
If I completely remove the entry spring.profiles.active from the application.properties, then the both the default profiles are utilized...
If the entry spring.profiles.active is added, then is it mandatory to list all the required profiles? Why can't it detect that for some profiles, default is to be used?
Is there any workaround for this?
From the reference guide
You can use a spring.profiles.active Environment property to specify which profiles are active. You can specify the property in any of the ways described earlier in this chapter. For example, you could include it in your application.properties, as shown in the following example:
spring.profiles.active=dev,hsqldb
You could also specify it on the command line by using the following switch: --spring.profiles.active=dev,hsqldb.
If no profile is active, a default profile is enabled. The name of the default profile is default and it can be tuned using the spring.profiles.default Environment property, as shown in the following example:
spring.profiles.default=none
You yourself specify which profiles are active, this isn't additive but it replaces it. So if you specify none then the default profile, by default named default (as shown above) is active, else only the profile(s) as specified by you
I need to load a property from a .yml file, which contains the path to a folder where the application can read files from.
I'm using the following code to inject the property:
#Value("${files.upload.baseDir}")
private String pathToFileFolder;
The .yml file for development is located under src/main/resources/config/application.yml, im running the application with the following command in production, to override the development settings:
java -jar app.jar --spring.config.location=/path/to/application-production.yml
The Spring Boot documentation says:
SpringApplication will load properties from application.properties files in the following locations and add them to the Spring Environment:
A /config subdirectory of the current directory.
The current directory
A classpath /config package
The classpath root
As well as:
You can also use YAML ('.yml') files as an alternative to '.properties'.
The .yml file contains:
{...}
files:
upload:
baseDir: /Users/Thomas/Code/IdeaProjects/project1/files
{...}
And my Application class is annotated with:
#SpringBootApplication
#EnableCaching
When I run the application, i get an exception:
Caused by: java.lang.IllegalArgumentException: Could not resolve placeholder 'files.upload.baseDir' in string value "${files.upload.baseDir}"
Do I have to use the YamlPropertySourceLoader class or add a special annotation to enable the support for .yml in Spring Boot?
Edit:
The .yml file contains some other properties, which get successfully loaded by Spring Boot like dataSource.XXXor hibernate.XXX.
For example: application.yml
key:
name: description here
Your Class:
#Value("${key.name}")
private String abc;
M. Deinum is right, the setup i've provided is working - the yml file was indented wrong, so the property couldn't be found.
I found the above wasn't working for me, because I tried to access the variable in a constructor. But at construction, the value is not injected yet.
Eventually I got it to work using this workaround: https://mrhaki.blogspot.com/2015/04/spring-sweets-using-value-for.html
Maybe this is helpful to others.
For me a duplicate key in the property file caused this...
I used same key unknowingly in large yml file.
key:
key1: value
key2: value
key:
key3: value
In yml properties file :
xxxx:
page:
rowSize: 1000
Create your Yaml properties config class :
#Configuration
#EnableConfigurationProperties
#ConfigurationProperties(prefix = "xxxx")
public class YmlPropertiesConfig {
private Page page;
public Page getPage() {
return page;
}
public void setPage(Page page) {
this.page = page;
}
public class Page {
private Integer rowSize;
public Integer getRowSize() {
return rowSize;
}
public void setRowSize(Integer rowSize) {
this.rowSize = rowSize;
}
}
}
Finally get it and use it :
public class XXXXController {
#Autowired
private YmlPropertiesConfig ymlProperties;
public String getIt(){
Integer pageRowSize = ymlProperties.getPage().getRowSize();
}
}
I've got that issue Caused by: java.lang.IllegalArgumentException: Could not resolve placeholder cause I've set test spring boot profile in properties.yaml.
Spring can't find properties for test profile when run app with no profile.
So remove spring boot profile from properties or yaml or run app with enabled profile.
Configuration file example is below:
#Configuration
public class AppConfig {
#Value("${prop.foo}")
private String foo;
#Value("${prop.bar}")
private String bar;
#Bean
BeanExample beanExample() {
return new BeanExample(foo, bar);
}
}
For those who have problems with a #RestController, I do it as follows:
#Autowired
#Value("${google.recaptcha}")
private String keyRecaptcha;
My properties file was mistakenly named applcation.properties as it was auto-generated by the Spring initializer. But I added the properties there in the .yml format and they were not retrieved with the same error.
When I renamed the file to application.yml, it started working.
In an application ther are multiple properties file for managing exception messages , alerts , and some others text these file like this :
- core-message.properties
- databaseException.properties
......
in Service layer maybe a database call occure and the database return a key that exist in one the properties files , and i want get the value and raise the exception messsage to user interface layer .
if i know that the key in wich properties file the code will be like this :
#Value("#{core['theExceptionKey']}")
public String excpetionMessage;
private void myMethod() {
throw new ExceptionClass(exceptionMessage);
}
i think spring can do that because when i use spring:message tag in jsp files spring does not know the key in witch file but it load the message correctly.
You can use Spring Environment abstraction for that.
First you need to add Property Source to your Java Configuration file
#Configuration
#PropertySource("classpath:/com/mypacakge/core-message.properties")
public class AppConfig {
Or if you have multiple properties files
#Configuration
#PropertySources({
#PropertySource("classpath:core-message.properties"),
#PropertySource("classpath:database.properties")
})
public class AppConfig {
Add PropertySourceConfigurer to to your Java Configuration file
#Bean
public static PropertySourcesPlaceholderConfigurer placeHolderConfigurer() {
return new PropertySourcesPlaceholderConfigurer();
}
Now let's say that in your core-message.properties you have the following data
message.name=Hello
You can retrieve this data in any bean by autowiring Environment abstraction and then calling env.getProperty()
#Autowired
Environment env;
public void m1(){
String message = env.getProperty("message.name")` // will return Hello
Environment object provides interface to configure property sources and resolve properties. It provides convenience to read from a variety of sources: properties files, system environment variable, JVM system properties, servlet context parameters, and so on, which is very useful. For example :
environment.getSystemProperties().put("message", "Hello");
System.getProperties().put("message", "Hello");
environment.getSystemProperties().get("message"); // retrieve property
environment.getPropertySources() // allows manipulation of Properties objects
Spring Reference Documentation - Environment
To get the value of the key programmatically you can use the following:
#Autowired
private Environment env;
...
String something = env.getProperty("property.key.something");
How to create project architecture to support multiple envionment. Each environment will have different datasource from different property file like(dev-propertfile,test-propertyFil,Production-propertyfile) with help of spring's
org.springframework.core.env.Environment;
I'll give step by step procedure for Spring boot applications.
Inside /src/main/resources/application.properties mention spring.profiles.active=dev (or Prod)
Create /src/main/resources/application-dev.properties and give your custom dev configurations here.
Create /src/main/resources/application-prod.properties and give your custom prod configurations here.
Run.
Put property file in same location as application.property and follow
the naming convention application-{profile}.properties like
application-dev.properties,application-test.properties,
application-prod.properties
And in application.properties set spring.profiles.active=dev,test etc
For Spring Boot applications it will work easily even by using a YAML File
spring:
profiles: dev
property: this is a dev env
---
spring:
profiles: prod
property: this is a production env
---
However, for a Spring MVC application, it needs more work. Have a look at this link
Basically, it involves 2 steps
Get the Spring Profile within servlet context
If you have set the profile on the server and want it to retrieve it within your application you can use System.getProperty or System.getenv methods.
Here is the code which fetches the profile and defaults it to a local profile, if no profile has been found.
private static final String SPRING_PROFILES_ACTIVE = "SPRING_PROFILES_ACTIVE";
String profile;
/**
* In local system getProperty() returns the profile correctly, however in docker getenv() return profile correctly
* */
protected void setSpringProfile(ServletContext servletContext) {
if(null!= System.getenv(SPRING_PROFILES_ACTIVE)){
profile=System.getenv(SPRING_PROFILES_ACTIVE);
}else if(null!= System.getProperty(SPRING_PROFILES_ACTIVE)){
profile=System.getProperty(SPRING_PROFILES_ACTIVE);
}else{
profile="local";
}
log.info("***** Profile configured is ****** "+ profile);
servletContext.setInitParameter("spring.profiles.active", profile);
}
To access the application-dev.properties, say now you will need to use
#Profile("dev") at the class level
The following code will fetch the application-dev.properties and common.properties
#Configuration
#Profile("dev")
public class DevPropertyReader {
#Bean
public static PropertyPlaceholderConfigurer properties() {
PropertyPlaceholderConfigurer ppc = new PropertyPlaceholderConfigurer();
Resource[] resources = new ClassPathResource[] { new ClassPathResource("properties/common.properties"), new ClassPathResource("properties/application-dev.properties") };
ppc.setLocations(resources);
ppc.setIgnoreUnresolvablePlaceholders(true);
return ppc;
}
}
For accessing say application-prod.properties you have to use #Profile("prod") at the class level. More details can be found here
Take a look at Spring Profile. You will define a set of profiles configurations, like Test, Dev, Production. And then, when you launch the application, you can define wich profile it should use.
Here are some tutorials of how to use.
And this guys had the same problem as yours: How to config #ComponentScan dynamic?
We wanted a way to load different properties from application-<your_env>.properties file depending on the environment (spring profile) in a Spring MVC project, so we implemented a configuration class something like this.
#Configuration
#PropertySource({ "classpath:application-${envTarget:dev}.properties" })
#Data
public class EnvironmentConfig {
#Value("${files.s3.accessId:}")
String s3AccessId;
#Value("${files.s3.accessToken:}")
String s3AccessToken;
.
.
.
}
Then we loaded the EnvironmentConfig in the class where we needed to use it.
While running the application, you just need to pass the -DenvTarget=<your_env>, and it will pick up the application-<your_env>.properties file from src/resources folder of the project.
In the above code, it will load values from application-dev.properties files when no envTarget is specified.
Thanks to Karthikeyan Muthurangam for suggesting this clever solution.