Spring Datasources based on Environment - java

I am trying to configure my Spring Boot application to use specific datasources when certain environmental variables exist. For example, if the MY_PROD_DATASOURCE environmental variable exists, I would like to use my production datasource; otherwise, I would like to use my local datasource (of the same type).
I have found something in the Spring reference that explains how a single datasource could be declared in my application.properties. Specifically, a MySQL datasource could look like:
spring.datasource.url=jdbc:mysql://localhost/test
spring.datasource.username=dbuser
spring.datasource.password=dbpass
spring.datasource.driverClassName=com.mysql.jdbc.Driver
However, I do not see how I could change the datasource properties conditionally in this file. Is there another way to do it?

In Spring Boot you can:
Externalize application.properties from your jar and provide file per environment by adding path as a startup parameter:
java -jar your-app.jar --spring.config.location=/path/to/app.properties
Use Spring profiles. Create application-${profile}.properties for each profile, in each one different datasource properties
Use Spring profiles and instead of application.properties, put your properties to application.yaml where you can put properties for all environments using convention as below:
spring:
profiles: development
server:
port: 9001
---
spring:
profiles: production
server:
port: 0
Use environment variables and set SPRING_DATASOURCE_URL, SPRING_DATASOURCE_USERNAME, SPRING_DATASOURCE_PASSWORD, and (optionally) SPRING_DATASOURCE_DRIVER_CLASS_NAME.
Learn more in the Spring Boot reference section on How to change configuration depending on the environment and External Configuration.

Related

How does spring boot know which property file to use based on environment

I have 4 files in my project:
application.properties
application-dev.properties
application-qa.properties
application-prod.properties
application.properties has a property spring.profiles.active = #active.profile#
When running on local, it uses application-dev.properties file. But in UAT and Prod, it uses respective property files. My question is how does spring boot know to use dev when im running in local and and qa in uat and prod in prod?
What does #active.profile# mean?
This is decided by the "profiles" variable. This is a Set<String>.
The exact way spring detect the profiles depends on the way you run your application.
The most common way is through the System Parameter: -Dspring.profiles.active=dev. So I assume somwhere in your production enviroment this variable gets set.
Alternativelly, if you run your spring app via a builder, you can define the profiles explicitly (code is in kotlin):
SpringApplicationBuilder(MyApp::class.java)
.profiles(*profiles)
.run(*args)
Check this article for more info: https://www.baeldung.com/spring-profiles

Spring Boot read environment variables inside application-properties

So I have been trying to figure out how to use environment-variables in either application.properties or application.yaml. Since this works in countless frameworks (such as Laravel for example), I assumed this would also work in Spring Boot. Now as I have found out, this is not the case.
I saw a post about Spring Environment API, that started that the environment-variable SPRING_DATASOURCE_URL would be equivalent to setting spring.datasource.url inside my application. However, this also didn't work for me.
Is there any quick way that allows using variables that are declared inside a .env file?
I'd like to use it like this inside the application.properties if possible.
spring.datasource.url=jdbc:postgresql://${DB_HOST}:${DB_PORT}/${DB_NAME}
.env is way of Python. If you use spring cloud, you can read env variable from configServer then inject them into application.properties.
add some dependency into pom.xml
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
define a yml to locate config-server. for example, called myBootstrap.yml
spring:
cloud:
config:
fail-fast: true
uri: http://[config-server-git]
name: cc
profile: config
label: maste
define a file named cc-config.properties and push it into config-server git. The env variables are written in this properties.
use below way to run application jar
java -jar [your-application-jar] --spring.cloud.bootstrap.location=myBootstrap.yml

Automatization Spring Cloud Profile

Actually have a little problem.
I want switch the url of my bootstrap.yml
It looks as follows:
spring:
application:
name: <project-name>
profiles:
active: dev
cloud:
config:
uri: http://<git-repository>:8080
fail-fast: false
This works, but i want have an propertie or anything what can switch if are in local or another enviroment.
I try to see this documentation but dont see any work for me.
I don't think Spring Cloud is any different from any Spring application, so you could use the Spring profiles.
Something similar is suggested on this answer: https://stackoverflow.com/a/22759706/6908551.
You could define a separate .yml file just for your cloud config uri, like cloud-config-dev.yml, cloud-config-prod.yml. Then, for a Java config, you could have something like:
#Configuration
public class MyApplicationConfiguration {
#Bean
public static PropertySourcesPlaceholderConfigurer propertyPlaceholderConfigurer() {
String activeProfile = System.getProperty("spring.profiles.active", "production");
String ymlFilename = "cloud-config-" + activeProfile + ".yml";
PropertySourcesPlaceholderConfigurer configurer = new PropertySourcesPlaceholderConfigurer();
configurer.setLocation(new ClassPathResource(ymlFilename));
return configurer;
}
}
I would define a bootstrap.yml file by environment.
Define a default bootstrap.yml in src/main/resources and define a specific bootstrap.yml file for each environment.
Then there are multiple ways.
Not exhaustive :
1) For each environment where the configuration file differs, run your spring boot jar by specifying the system property spring.cloud.bootstrap.location with the expected value such as :
java -jar ... -Dspring.cloud.bootstrap.location=bootstrap-dev.yml ....
That overrides the current location of that file.
2) Take advantage of Spring Boot profile feature : bootstrap.yml is compatible with. For example if the dev profile is enabled, the bootstrap-dev.properties in the classpath will be used.
I tend to use the first way because that is more explicit for non Spring Boot users.
Source : 1.3 Changing the Location of Bootstrap Properties

How to select profiles in spring-boot

I have application files according to my environment: application.yml and application-uat.yml. I'm running the application by providing the SPRING_PROFILES_ACTIVE as environment variable so that the correct file is selected. I have a problem with defining additional profiles inside application.
Suppose I have a bean with profile mock-rest that mocks the rest client and I have a bean with profile actual-rest.
I've tried two do it in those ways:
#inside application.yml
spring:
profiles:
include: mock-rest
And for UAT:
#inside application-uat.yml
spring:
profiles:
include: actual-rest
But the problem is that spring will include both profiles, because it takes the both files and only replaces the values from uat yml file.
If I try to use spring.profiles.active inside yml files Spring will ignore that as the SPRING_PROFILES_ACTIVE environment variable will have priority.
So, the question is what is the way to overcome described problem? Basically, I need to define profiles inside application.yml files and I want to only define environment as my SPRING_PROFILES_ACTIVE env variable. Is this possible? If not, what are my options to consider?
The application.yml file is read whatsoever. This is an indented behaviour. Usually, all values in application.yml would be overrided by other more specific application-*.yml.
But profiles are not a single values, you can have multiple one enabled at the same time, so i does not oeverride the profile, instead it cumulate both.
If you want to get rid of the mock-rest on prod environment you might want to remove the mock-rest profile from application.yml and move it to a new application-mock.yml that you can activate using an environment variable.
application.yml
# some default configuration
application-mock.yml
spring:
profiles:
include: actual-rest
application-uat.yml
spring:
profiles:
include: actual-rest

Spring Boot 2 use dev profile if prod profile is not exist

I have Spring Boot Application and i have 3 property files: applications.properties, applications-dev.properties, applicaton-prod.properties. In applications.properties i specify that spring.profiles.active=prod. But I want to allow startup of application without prod profile(applicaton-prod.properties). It means that spring must startup application in dev profile(applications-dev.properties) automatically. How can i implement this? May be some MissingOnProfile annotation exist?) My task is to create different application behaviour based on application.properties files. Also i use #Profile annotation in each bean that depends on particular profile. All task is to create WebInstaller, and in finish step i will create application-prod.properties and by using RestartEndpoint i will restart application context and required beans from application-prod.properties will injected. But i need to make startup withoud application-prod.properties, but if this file exist i will startup in prod profile.
You can do this:
SpringApplication application = new SpringApplication(IdMatrixApplication.class);
File file = new File("src/main/resources/dev/application-prod.properties");
if (file.exists()) {
application.setAdditionalProfiles("prod","dev");
}
application.run(args);
You are setting the profile information in the wrong place. The file application.properties contains properties that are common to all profiles (dev, stage, prod etc). For profiles you should, as you suggested, create a file of the name application-{profile}.properties which will override certain properties according to the environemnt defined by variable profile.
The usual approach is to pass this variables as parameters to the JVM (e.g:-Dprofile=dev), which you can set by modifying the run configuration of the servlet container if you are launching from an IDE. In case of a stand-alone tomcat you can pass this information through JAVA_OPTIONS variable found in the file setenv.sh.
If you need to manually implement some kind of business logic with profiles, for example, specify that the active profile by default prod
In application.properties define spring.profiles.active=prod
and for example if the application-prod.properties is missing, then the active profile should be the dev, you can implement this with EnvironmentPostProcessor:
Allows for customization of the application's Environment prior to the application context being refreshed
Implement EnvironmentPostProcessor with your business logic
public class ProfileResolverEnvironmentPostProcessor implements EnvironmentPostProcessor {
#Override
public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {
ClassPathResource prodPropertiesResource = new ClassPathResource("application-prod.properties");
// if "application-prod.properties" missing and "prod" profile active
if (!prodPropertiesResource.exists() && environment.acceptsProfiles("prod")) {
environment.setActiveProfiles("dev");
//environment.addActiveProfile("dev");
}
}
}
Register your EnvironmentPostProcessor implementation class in META-INF/spring.factories
org.springframework.boot.env.EnvironmentPostProcessor=\
com.example.ProfileResolverEnvironmentPostProcessor
Also, take look at Spring Boot documentation Customize the
Environment
Additional:
Of course, you can specify beans that will be active if the profile is missing #Profile("!prod")
But this does not work in your case if you define spring.profiles.active=prod, because the active profile prod will be in the Environment but it has nothing to do with the fact that the application-prod.properties is missing
If you want this then why you need application-dev.properties. Keep Your dev properties in application.properties. If profile set then applicatoin.properties value will be overwrite. Spring boot read both application.properties && application.yml and replace value if profile active

Categories

Resources