24

I have a spring boot application which interacts with DB to provide resource using Spring data Rest. I want to get the configuration from environment variables. Below is my properties file.

spring.datasource.url=${mysql.url}
spring.datasource.username=${mysql.user}
spring.datasource.password=${mysql.password}

And my environment variables are in the image https://ibb.co/cyxsNc

I even tried with the below config too

spring.datasource.url=${MySQL_Url}
spring.datasource.username=${MySQL_User}
spring.datasource.password=${MySQL_Password}

But I am not able to connect to the DB and getting the below error

org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration': Unsatisfied dependency expressed through constructor parameter 0; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'dataSource' defined in class path resource [org/springframework/boot/autoconfigure/jdbc/DataSourceConfiguration$Tomcat.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.apache.tomcat.jdbc.pool.DataSource]: Factory method 'dataSource' threw exception; nested exception is java.lang.IllegalArgumentException: URL must start with 'jdbc'

Application folder structure

Project
|-- src/main/java
    |-- com.example.app
        |-- DemoApplication.java
|-- src/main/resources
    |-- application.properties

Note: The configuration works fine if I set the values like below

spring.datasource.url=jdbc:mysql://localhost:3306/ex_man
spring.datasource.username=root
spring.datasource.password=root

What am I missing?

Ken Williams
  • 22,756
  • 10
  • 85
  • 147
Sesha
  • 565
  • 1
  • 7
  • 20
  • 1
    Don't use a screenshot, as the host could go down. A code excerpt is preferable. –  Feb 20 '18 at 19:46
  • @Sp Sesha, please post your main configuration class (if any) and project structure. Most likely your application context is not picking up your application.properties file (should be on your classpath). – Urosh T. Feb 20 '18 at 20:05
  • Well then your environment variables are not loaded with your application. How do you load them into the project? – Urosh T. Feb 20 '18 at 21:14
  • where you able to solve your problem? – Cerbis Apr 26 '18 at 13:00
  • Possible duplicate of [Using env variable in Spring Boot's application.properties](https://stackoverflow.com/questions/35531661/using-env-variable-in-spring-boots-application-properties) – Alex R Oct 11 '18 at 02:45

2 Answers2

18

Check out this documentation here: https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-external-config.html

try naming your environment variables:

SPRING_DATASOURCE_URL

SPRING_DATASOURCE_USERNAME

SPRING_DATASOURCE_PASSWORD

UPDATE:

Spring boot does properly pick up the environment variables, see test below.

package com.example.environment_vars;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;

import java.util.Map;      // Import this for systemEnvironment

@SpringBootApplication
public class EnvironmentVarsApplication {

    @Value("#{systemEnvironment['ENV_VAR'] ?: 'Default_value'}")
    private String envVar;
    
    @Bean
    public CommandLineRunner commandLineRunner() {
        return new CommandLineRunner() {
            @Override
            public void run(String[] arg0) throws Exception {
                System.out.println(envVar);
            }
        };
    }
    
    public static void main(String[] args) {
        SpringApplication.run(EnvironmentVarsApplication.class, args);
    }
}

This will print out the value of the environment variable ENV_VAR and if the value is not present, it will print the Default_Value.

@Value injects the value accessible throughout the project.

Udith Indrakantha
  • 860
  • 11
  • 17
Steve
  • 939
  • 1
  • 6
  • 20
  • Do I need to have a default value specified in the properties file or the environmental variables is enough? – Sesha Feb 20 '18 at 19:49
  • According to the docs the environment variable should be enough, I haven't tested this out though. Give it a quick test and if it doesn't work we can try another method. – Steve Feb 20 '18 at 20:25
  • If I try without a default value in properties file, I am getting an error saying the application failed to start and the description is `Cannot determine embedded database driver class for database type NONE` – Sesha Feb 20 '18 at 20:28
  • Did you make sure to export the environment variables? In the update above I tested and confirmed that the environment variables are picked up by spring boot. Are you running in tomcat or another web server? That may affect access to the environment variables. – Steve Feb 20 '18 at 21:01
  • I am confirming that application.properties entries are working for me : spring.datasource.url=${SPRING_DATASOURCE_URL} spring.datasource.username=${SPRING_DATASOURCE_USERNAME} spring.datasource.password=${SPRING_DATASOURCE_PASSWORD} – granadaCoder Jan 17 '19 at 19:58
  • and I just tested with application.yml spring: datasource: url: ${SPRING_DATASOURCE_URL} username: ${SPRING_DATASOURCE_USERNAME} password: ${SPRING_DATASOURCE_PASSWORD} – granadaCoder Jan 17 '19 at 19:59
  • What if I want to use some other environment variable name. Say PROD_DATASOURCE_USERNAME? I tried spring.datasource.username=${PROD_DATASOURCE_USERNAME} but it is still picking up SPRING_DATASOURCE_USERNAME. I have both SPRING_DATASOURCE_USERNAME and PROD_DATASOURCE_USERNAME as environment vars – Chintan Pandya Sep 16 '19 at 09:02
  • @chintanPandya you don't need to put that in your application.yml , Spring automatically picks the env vars and use them instead of reading the file. So you can remove all of that from your file – GabrielBB Jul 30 '20 at 07:49
  • Same for @granadaCoder "spring.datasource.url=${SPRING_DATASOURCE_URL}" is redundant. You can remove that – GabrielBB Jul 30 '20 at 07:50
  • Where is it specified in the doc how ENV variables are converted to spring properties? – Aleksandr Erokhin Sep 30 '20 at 08:01
  • 2
    @AleksandrErokhin You can find the conversion documentation here: https://docs.spring.io/spring-boot/docs/current/reference/html/spring-boot-features.html#boot-features-external-config-relaxed-binding-from-environment-variables – Tom Oct 20 '20 at 08:50
7

You can use a DataSource configuration file and obtain environment variables using System.getEnv("ENV_VARIABLE") method.

First you should remove properties starting with "spring.datasource." in application.properties. Then include this ready to go configuration file:

import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.sql.DataSource;

@Configuration
class JpaConfig {

    @Bean
    public DataSource getDataSource() {
        return DataSourceBuilder.create()
                .driverClassName("com.mysql.cj.jdbc.Driver")
                .url(getDataSourceUrl())
                .username(System.getenv("DB_USERNAME"))
                .password(System.getenv("DB_PASSWORD"))
                .build();
    }

    private String getDataSourceUrl() {
        return "jdbc:mysql://"
                + System.getenv("DB_HOST") + "/"
                + System.getenv("DB_NAME")
                + "?allowPublicKeyRetrieval=true&useSSL=false&serverTimezone=UTC&useLegacyDatetimeCode=false";
    }
}
Rubén Morales
  • 332
  • 4
  • 6