Using env variable in Spring Boot application.properties

We are working on the Spring Boot web application, and the database we use is MySql ;

  • we have settings that we first test locally (this means that we need to install MySql on our PC);

  • then we click on bitbucket ;

  • Jenkins automatically detects a new push request to Bitbucket and builds it (in order to transfer Jenkins mvn build, we also need to install MySql on the virtual machines running Jenkins).

  • if the Jenkins build is successful, we send the code to our application in OpenShift (using the Openshift deployment plugin in Jenkins).

The problem we are facing, as you may have already understood, is this:

  • in application.properties we cannot hardcode MySql information. Since our project will be executed in 3 different places (local, Jenkins and OpenShift), we need to make the data source field dynamic in application.properties (we know that there is another way to do this, but we are working on this solution now),

     spring.datasource.url = spring.datasource.username = spring.datasource.password = 

The solution we came up with is that we create system environment variables locally and in Jenkins vm (naming them the same as OpenShift calls them) and assigning them the correct values ​​respectively:

 export OPENSHIFT_MYSQL_DB_HOST="jdbc:mysql://localhost" export OPENSHIFT_MYSQL_DB_PORT="3306" export OPENSHIFT_MYSQL_DB_USERNAME="root" export OPENSHIFT_MYSQL_DB_PASSWORD="123asd" 

We did it and it works. We also checked with Map<String, String> env = System.getenv(); that environment variables can be converted to Java variables as such:

 String password = env.get("OPENSHIFT_MYSQL_DB_PASSWORD"); String userName = env.get("OPENSHIFT_MYSQL_DB_USERNAME"); String sqlURL = env.get("OPENSHIFT_MYSQL_DB_HOST"); String sqlPort = env.get("OPENSHIFT_MYSQL_DB_PORT"); 

Now it remains only to use these java variables in our application.properties and we have problems with this.

In which folder and how should we assign the variables password , userName , sqlURL and sqlPort to application.properties so that they can be seen, and how can we include them in application.properties ?

We tried many things, one of which:

 spring.datasource.url = ${sqlURL}:${sqlPort}/"nameofDB" spring.datasource.username = ${userName} spring.datasource.password = ${password} 

So far no luck. We probably do not put these env variables in the desired class / folder or use them incorrectly in application.properties .

Your help is much appreciated!

Thank!

+119
java spring spring-mvc mysql openshift
Feb 21 '16 at 2:39
source share
8 answers

You do not need to use Java variables. To enable the env system variables, add the following to the application.properties file:

 spring.datasource.url = ${OPENSHIFT_MYSQL_DB_HOST}:${OPENSHIFT_MYSQL_DB_PORT}/"nameofDB" spring.datasource.username = ${OPENSHIFT_MYSQL_DB_USERNAME} spring.datasource.password = ${OPENSHIFT_MYSQL_DB_PASSWORD} 

But the method suggested by @Stefan Isele is preferable because in this case you should only declare one env variable: spring.profiles.active . Spring will automatically read the corresponding property file using application-{profile-name}.properties .

+134
Feb 21 '16 at 10:48
source share
— -

The easiest way to have different configurations for different environments is to use spring profiles. See the external configuration .

This gives you great flexibility. I use it in my projects and it is very useful. In your case, you will have 3 profiles: "local", "jenkins" and "openshift"

Then you have 3 profile properties files: application-local.properties , application-jenkins.properties and application-openshift.properties

There you can set properties for the appropriate environment. When you launch the application, you must specify the profile to activate as follows: -Dspring.profiles.active=jenkins

edit

According to the spring document, you can set the system environment variable SPRING_PROFILES_ACTIVE to activate profiles and do not need to pass it as a parameter.

Is there a way to pass an active profile setting for a web application at runtime?

No. Spring defines active profiles as one of the first steps in building an application context. Active profiles are then used to decide which property files will be read and which components will be created. After starting the application, this cannot be changed.

+44
Feb 21 '16 at 10:30
source share

This is in response to a number of comments, as my reputation is not high enough to comment directly.

You can specify a profile at runtime while the application context has not yet been loaded.

 // Previous answers incorrectly used "spring.active.profiles" instead of // "spring.profiles.active" (as noted in the comments). // Use AbstractEnvironment.ACTIVE_PROFILES_PROPERTY_NAME to avoid this mistake. System.setProperty(AbstractEnvironment.ACTIVE_PROFILES_PROPERTY_NAME, environment); ApplicationContext applicationContext = new ClassPathXmlApplicationContext("/META-INF/spring/applicationContext.xml"); 
+7
Oct 19 '16 at 19:07
source share

Here is a snippet of code through a chain of environment properties files loaded for different environments.

Properties file under the resources of your application ( src / main / resources ): -

  1. application.properties 2. application-dev.properties 3. application-uat.properties 4. application-prod.properties 

Ideally, application.properties contains all the common properties that are available for all environments, and properties related to the environment only work in certain environments. therefore, the loading order of these property files will be like this:

  application.properties -> application.{spring.profiles.active}.properties. 

Code snippet here: -

  import org.springframework.context.support.PropertySourcesPlaceholderConfigurer; import org.springframework.core.io.ClassPathResource; import org.springframework.core.io.Resource; public class PropertiesUtils { public static final String SPRING_PROFILES_ACTIVE = "spring.profiles.active"; public static void initProperties() { String activeProfile = System.getProperty(SPRING_PROFILES_ACTIVE); if (activeProfile == null) { activeProfile = "dev"; } PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer = new PropertySourcesPlaceholderConfigurer(); Resource[] resources = new ClassPathResource[] {new ClassPathResource("application.properties"), new ClassPathResource("application-" + activeProfile + ".properties")}; propertySourcesPlaceholderConfigurer.setLocations(resources); } } 
+5
Aug 04 '17 at 17:51 on
source share

Flayway does not recognize direct environment variables in application.properties (Spring-Boot V2.1). eg

 spring.datasource.url=jdbc:mysql://${DB_HOSTNAME}:${DB_PORT}/${DB_DATABASE} spring.datasource.username=${DB_USER} spring.datasource.password=${DB_PASS} 

To solve this problem, I made this environment variable, usually I create a .env file:

 SPRING_DATASOURCE_URL=jdbc:mysql://127.0.0.1:3306/place SPRING_DATASOURCE_USERNAME=root SPRING_DATASOURCE_PASSWORD=root 

And export the variables to my environment:

 export $(cat .env | xargs) 

And finally, just run the command

 mvn spring-boot:run 

Or run the JAR file

 java -jar target/your-file.jar 

There is another approach here: https://docs.spring.io/spring-boot/docs/2.1.0.BUILD-SNAPSHOT/maven-plugin/examples/run-env-variables.html.

+3
Dec 15 '18 at 22:09
source share

Using Spring context 5.0 I successfully managed to load the correct properties file based on the system environment using the following annotation

 @PropertySources({ @PropertySource("classpath:application.properties"), @PropertySource("classpath:application-${MYENV:test}.properties")}) 

Here, the MYENV value is read from the system environment, and if there is no system environment, then the default test environment properties file will be loaded, if I give the wrong MYENV value, it will not be able to start the application.

Note: for each profile that you want to save, you will need to create an application- [profile] .property file, and although I used Spring context 5.0 & not Spring boot . I believe this will also work on Spring 4.1

+2
Nov 25 '17 at 6:36
source share

I might write it too late, but I had a similar problem when I tried to override property reading methods.

My problem: 1) Reading a property from env if this property was set to env 2) Reading a property from a system property if this property was set to a system property 3) And the last, read from the application properties.

So, to solve this problem, I go into my bean class

 @Validated @Configuration @ConfigurationProperties(prefix = ApplicationConfiguration.PREFIX) @PropertySource(value = "${application.properties.path}", factory = PropertySourceFactoryCustom.class) @Data // lombok public class ApplicationConfiguration { static final String PREFIX = "application"; @NotBlank private String keysPath; @NotBlank private String publicKeyName; @NotNull private Long tokenTimeout; private Boolean devMode; public void setKeysPath(String keysPath) { this.keysPath = StringUtils.cleanPath(keysPath); } } 

And rewrite factory in @PropertySource. And then I created my own implementation for reading properties.

  public class PropertySourceFactoryCustom implements PropertySourceFactory { @Override public PropertySource<?> createPropertySource(String name, EncodedResource resource) throws IOException { return name != null ? new PropertySourceCustom(name, resource) : new PropertySourceCustom(resource); } } 

And created a PropertySourceCustom

 public class PropertySourceCustom extends ResourcePropertySource { public LifeSourcePropertySource(String name, EncodedResource resource) throws IOException { super(name, resource); } public LifeSourcePropertySource(EncodedResource resource) throws IOException { super(resource); } public LifeSourcePropertySource(String name, Resource resource) throws IOException { super(name, resource); } public LifeSourcePropertySource(Resource resource) throws IOException { super(resource); } public LifeSourcePropertySource(String name, String location, ClassLoader classLoader) throws IOException { super(name, location, classLoader); } public LifeSourcePropertySource(String location, ClassLoader classLoader) throws IOException { super(location, classLoader); } public LifeSourcePropertySource(String name, String location) throws IOException { super(name, location); } public LifeSourcePropertySource(String location) throws IOException { super(location); } @Override public Object getProperty(String name) { if (StringUtils.isNotBlank(System.getenv(name))) return System.getenv(name); if (StringUtils.isNotBlank(System.getProperty(name))) return System.getProperty(name); return super.getProperty(name); } } 

So that helped me.

+1
Jul 04 '17 at 9:52 on
source share

I ran into the same problem as the author of the question. For our case, the answers to this question were not enough, because each of my team members had their own local environment, and we definitely needed a .gitignore file that had a different connection string for .gitignore data and credentials so that people would not transfer the Distributed file mistakenly and disconnecting from others.

On top of that, when we followed the procedure below, it was easy to deploy in different environments, and as an added bonus, we didn't need to have any confidential information in version control at all .

Extracting an idea from the PHP environment of Symfony 3, which has parameters.yml (.gitignored) and parameters.yml.dist (an example that creates the first file with composer install ),

I did the following, combining the knowledge from the answers below: https://stackoverflow.com/a/166127/

In essence, this gives you the freedom to use spring configuration inheritance and select active profiles through the configuration at the top, plus any additional sensitive credentials as follows:

application.yml.dist (sample)

  spring: profiles: active: local/dev/prod datasource: username: password: url: jdbc:mysql://localhost:3306/db?useSSL=false&useLegacyDatetimeCode=false&serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8 

application.yml (.gitignore-d on the development server)

 spring: profiles: active: dev datasource: username: root password: verysecretpassword url: jdbc:mysql://localhost:3306/real_db?useSSL=false&useLegacyDatetimeCode=false&serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8 

application.yml (.gitignore-d on the local machine)

 spring: profiles: active: local datasource: username: root password: rootroot url: jdbc:mysql://localhost:3306/xampp_db?useSSL=false&useLegacyDatetimeCode=false&serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8 

application-dev.yml (additional properties independent of the environment)

 spring: datasource: testWhileIdle: true validationQuery: SELECT 1 jpa: show-sql: true format-sql: true hibernate: ddl-auto: create-droop naming-strategy: org.hibernate.cfg.ImprovedNamingStrategy properties: hibernate: dialect: org.hibernate.dialect.MySQL57InnoDBDialect 

You can do the same with .properties

+1
Nov 08 '18 at
source share



All Articles