Spring Boot overriding YML profile from Command Line - spring

I wan't to override an existing YML file profile using command line, so I did this.
Created a folder and added to the classpath
Copied another application.yml in that new folder
Ran this command mvn spring-boot:run -Dspring.profiles.active=unit-test
but it still picking up the "default" active profile from the source code application.yml. I also tried creating a application.properties instead of application.yml but it still didn't get picked up?
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
#Configuration
#EnableAutoConfiguration
#ComponentScan
public class SuchApplication implements CommandLineRunner {
#Autowired
private DogeService dogeService;
#Override
public void run(String... args) {
System.out.println("AutoConfiguration should have wired up our stuff");
System.out.println("Let's see if we are doge-worthy...");
if (dogeService.requiresDogeness()) {
System.out.println(dogeService.leDoge());
} else {
System.out.println("No Doge for us :(");
}
}
public static void main(String[] args) throws Exception {
SpringApplication.run(SuchApplication.class, args);
}
}
I have the following YML file under my resources folder
spring:
profiles.active: default
---
spring:
profiles: default
doge:
wow: 10
such: so
very: true
---
spring:
profiles: unit-test
doge:
wow: 4
such: so
very: true

I had a similar problem with Spring Boot and resolved it with this annotation in my configuration class...
#PropertySource("classpath:application.yml")
But from the official Spring documentation, this annotation looks unnecessary, which is why I did not add on the first attempt.

Related

Property resolving for multiple Spring profiles (yaml configuration)

Is there a defined order when multiple profiles are used for a property resolution.
I have yaml configuration file:
name: none
---
spring:
profiles: prod
name: prodName
---
spring:
profiles: dev
name: devName
When application runs with no (default) profile, none is printed. For dev/prod profiles devName/prodName is printed (so far so good).
When I tried to define profile as dev,prod prodName is printed,when I specify prod,dev devName is printed.
Is this something I can rely on? I mean is it specified in Spring? I didn't find it here.
full version (for replication)
application.yml
name: none
---
spring:
profiles: dev
name: devName
---
spring:
profiles: prod
name: prodName
Configuration.java
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.List;
#Component
#ConfigurationProperties
public class Configuration {
String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
SpringBootConsoleApplication.java
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import java.util.List;
#SpringBootApplication
public class SpringBootConsoleApplication implements CommandLineRunner {
private static Logger LOG = LoggerFactory.getLogger(SpringBootConsoleApplication.class);
#Autowired
Configuration conf;
public static void main(String[] args) {
SpringApplication.run(SpringBootConsoleApplication.class, args);
}
#Override
public void run(String... args) {
LOG.info("name: {}", conf.name);
}
}
edit:
GitHub repository
sample output:
c:\betlista\SpringPropertyResolutionMultipleProfiles>java -jar target\spring-boot-console-app-1.0.jar
...: name: none, label: labelValue
c:\betlista\SpringPropertyResolutionMultipleProfiles>java -jar -Dspring.profiles.active=dev target\spring-boot-console-app-1.0.jar
...: name: devName, label: labelValue
c:\betlista\SpringPropertyResolutionMultipleProfiles>java -jar -Dspring.profiles.active=dev,prod target\spring-boot-console-app-1.0.jar
...: name: prodName, label: labelValue
c:\betlista\SpringPropertyResolutionMultipleProfiles>java -jar -Dspring.profiles.active=prod,dev target\spring-boot-console-app-1.0.jar
...: name: devName, label: labelValue
edit 2:
Topics
There was a question which I'd refer to as topics - Multiple properties file for a single spring profile
While one can use #PropertySource with property files, it cannot be used with YAML files. The only solution I know at the moment is to used e.g. -Dspring.config.additional-location=classpath:topic1.yml
edit 3:
The "duplicate" question has same questions as I have here, but without an answer. That question was about beans, not really a properties. Accepted answer says "spring.profiles.active system property doesn't matter.", which I shown as incorrect (within context of properties). Please vote for reopen if you agree.
Is this something I can rely on?
Yes, the last-win strategy is consistent and is documented in the reference guide:
If several profiles are specified, a last-wins strategy applies. For example, if profiles prod,live are specified by the spring.profiles.active property, values in application-prod.properties can be overridden by those in application-live.properties.
(Unrelated, but about the link to the doc you've shared. I don't know if that's an accident but that's the documentation for Spring Boot 1.2.x which was released over 6 years ago).

Error Messages as Key Value Pairs - from a Properties File in classpath - Spring boot 2.0

We are currently on a Spring Boot Version 1.x
We have Error Messages (Error Key -> Error Code) pairs in our error.properties file (this is in the class path).
We leveraged PropertiesConfigurationFactory to get these Error Key and Error Code pairs in to a POJO, this POJO had a Map
Hence very convenient to be used across our application to get an Error code for a given Error Key.
What is its equivalent in Spring Boot 2.x ?.
Assuming you have error.properties file with the below contents:
errors.error1=101
errors.error2=102
errors.error3=103
A simple spring boot app that demonstrates the injection of these properties :
package snmaddula.remittance;
import java.util.Map;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.PropertySource;
#SpringBootApplication
#ConfigurationProperties
#PropertySource("classpath:error.properties")
public class DemoApplication {
private Map<String, Integer> errors;
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
#Bean
public CommandLineRunner cli() {
return (args) -> {
System.out.println(errors); // you can print and see the error properties injected to this map.
};
}
public void setErrors(Map<String, Integer> errors) {
this.errors = errors;
}
}
With the use of #PropertySource and #ConfigurationProperties we can enable property injection provided we have a setter method for our attribute.
When you run this program, you can see the properties getting printed on to the console as I added a CommandLineRunner cli() {..} to show the working of it.
The working sample is available on GitHub.

Autowiring Issue with using Springboot PropertiesFactoryBean

I am new to Springboot PropertiesFactoryBean and want to inject a file from classpath so that I can populate it into a Map
Location of properties file on Eclipse: src/main/resources
contents of File: simple_property.properties:
key1=value1
key2=value2
key3=value3
My ApplicationConfiguration.java looks as below:
import org.springframework.beans.factory.config.PropertiesFactoryBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
#Configuration
public class ApplicationConfiguration {
#Bean(name = "simpleMapping")
public static PropertiesFactoryBean artifactMapping() {
PropertiesFactoryBean bean = new PropertiesFactoryBean();
bean.setLocation(new ClassPathResource("simple_property.properties"));
return bean;
}
}
I have a ApplicationRunner interface for bean to be run:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
#SpringBootApplication
public class pCli implements ApplicationRunner {
#Autowired
private SomeClass someProgram;
public static void main(String[] args) {
SpringApplication.run(pCli.class, args);
}
#Override
public void run(ApplicationArguments args) throws Exception {
someProgram.run(args.getOptionValues("param1").get(0));
}
}
I am unable to understand & proceed ahead how I can use bean to read all properties ? Example how I can get the properties into a variable of Map and access them ? (If #Autowired has already loaded the properties file from classpath then how can I access it ? )
Say you have your map in the property file like this,
app.number-map={KEY1:1, KEY2:2, KEY3:3}
You can use this value by injecting the property using the #Value annotation. Following is an example where the value is injected to a method. Spring expression #{${app.number-map}} will fetch the value in the properties file.
someMethod(#Value("#{${app.number-map}}")
Map<String, Integer> numberMap) {
// ...
}
Use application.properties since you're still learning. It'll make your life easy. Also, keeping a separate configuration bean would really help you to manage and access property values easily.

How to display "welcome.jsp" in spring boot?

Facing issues while displaying customized welcome.jsp in spring boot application.
It always displays "index.html" while I want to display customized jsp file "welcome.jsp"..
Request help.
1) make sure springmvc options in application.properties
spring.mvc.view.prefix: /WEB-INF/jsp/
spring.mvc.view.suffix: .jsp
2) add src/main/webapp/WEB-INF/jsp/welcome.jsp
3) modify Application like this:
package com.lenicliu.spring.boot;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
#SpringBootApplication
public class Application extends WebMvcConfigurerAdapter {
public static void main(String[] args) throws Exception {
SpringApplication.run(Application.class, args);
}
#Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/").setViewName("welcome");
}
}
Please refer to http://docs.spring.io/spring/docs/4.2.6.RELEASE/spring-framework-reference/htmlsingle/#mvc-config-view-controller
Then, run application, and you can find the log:
Root mapping to handler of type [class org.springframework.web.servlet.mvc.ParameterizableViewController]

Disable all Database related auto configuration in Spring Boot

I am using Spring Boot to develop two applications, one serves as the server and other one is a client app. However, both of them are the same app that function differently based on the active profile. I am using auto configuration feature of Spring Boot to configure my applications.
I want to disable all the database related auto configuration on client app, since it won't be requiring database connection. Application should not try to establish connection with the database, nor try to use any of the Spring Data or Hibernate features. The enabling or disabling of the database auto configuration should be conditional and based on the active profile of the app.
Can I achieve this by creating two different application.properties files for respective profiles?
I tried adding this to my properties file,
spring.autoconfigure.exclude=org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration\
org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration\
org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration\
org.springframework.boot.autoconfigure.data.web.SpringDataWebAutoConfiguration
But, the application still tries to connect to the database on start. Are those exclusions sufficient for achieving my requirement?
The way I would do similar thing is:
#Configuration
#EnableAutoConfiguration(exclude = {DataSourceAutoConfiguration.class, DataSourceTransactionManagerAutoConfiguration.class, HibernateJpaAutoConfiguration.class})
#Profile ("client_app_profile_name")
public class ClientAppConfiguration {
//it can be left blank
}
Write similar one for the server app (without excludes).
Last step is to disable Auto Configuration from main spring boot class:
#SpringBootApplication
public class SomeApplication extends SpringBootServletInitializer {
public static void main(String[] args) {
SpringApplication.run(SomeApplication.class);
}
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(SomeApplication.class);
}
}
Change: #SpringBootApplication into:
#Configuration
#ComponentScan
This should do the job. Now, the dependencies that I excluded in the example might be incomplete. They were enough for me, but im not sure if its all to completely disable database related libraries. Check the list below to be sure:
http://docs.spring.io/spring-boot/docs/current-SNAPSHOT/reference/htmlsingle/#auto-configuration-classes
For disabling all the database related autoconfiguration and exit from:
Cannot determine embedded database driver class for database type NONE
1. Using annotation:
#SpringBootApplication
#EnableAutoConfiguration(exclude = {
DataSourceAutoConfiguration.class,
DataSourceTransactionManagerAutoConfiguration.class,
HibernateJpaAutoConfiguration.class})
public class Application {
public static void main(String[] args) {
SpringApplication.run(PayPalApplication.class, args);
}
}
2. Using Application.properties:
spring.autoconfigure.exclude=org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration, org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration
Seems like you just forgot the comma to separate the classes. So based on your configuration the following will work:
spring.autoconfigure.exclude=org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration,\
org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration,\
org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration,\
org.springframework.boot.autoconfigure.data.web.SpringDataWebAutoConfiguration
Alternatively you could also define it as follow:
spring.autoconfigure.exclude[0]=org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration
spring.autoconfigure.exclude[1]=org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration
spring.autoconfigure.exclude[2]=org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration
spring.autoconfigure.exclude[3]=org.springframework.boot.autoconfigure.data.web.SpringDataWebAutoConfiguration
There's a way to exclude specific auto-configuration classes using #SpringBootApplication annotation.
#Import(MyPersistenceConfiguration.class)
#SpringBootApplication(exclude = {
DataSourceAutoConfiguration.class,
DataSourceTransactionManagerAutoConfiguration.class,
HibernateJpaAutoConfiguration.class})
public class MySpringBootApplication {
public static void main(String[] args) {
SpringApplication.run(MySpringBootApplication.class, args);
}
}
#SpringBootApplication#exclude attribute is an alias for #EnableAutoConfiguration#exclude attribute and I find it rather handy and useful.
I added #Import(MyPersistenceConfiguration.class) to the example to demonstrate how you can apply your custom database configuration.
Way out for me was to add
#EnableAutoConfiguration(exclude = {DataSourceAutoConfiguration.class, DataSourceTransactionManagerAutoConfiguration.class, HibernateJpaAutoConfiguration.class})
annotation to class running Spring boot (marked with `#SpringBootApplication).
Finally, it looks like:
#SpringBootApplication
#EnableAutoConfiguration(exclude = {DataSourceAutoConfiguration.class, DataSourceTransactionManagerAutoConfiguration.class, HibernateJpaAutoConfiguration.class})
public class Application{
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
If using application.yml:
spring:
autoconfigure:
exclude:
- org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration
- org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration
- org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration
- org.springframework.boot.autoconfigure.data.web.SpringDataWebAutoConfiguration
Another way to control it via Profiles is this:
// note: no #SpringApplication annotation here
#Import(DatabaseConfig.class)
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
#Configuration
#Import({DatabaseConfig.WithDB.class, DatabaseConfig.WithoutDB.class})
public class DatabaseConfig {
#Profile("!db")
#EnableAutoConfiguration(
exclude = {DataSourceAutoConfiguration.class, DataSourceTransactionManagerAutoConfiguration.class,
HibernateJpaAutoConfiguration.class})
static class WithoutDB {
}
#Profile("db")
#EnableAutoConfiguration
static class WithDB {
}
}
I had the same problem here, solved like this:
Just add another application-{yourprofile}.yml where "yourprofile" could be "client".
In my case I just wanted to remove Redis in a Dev profile, so I added a application-dev.yml next to the main application.yml and it did the job.
In this file I put:
spring.autoconfigure.exclude: org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration,org.springframework.boot.autoconfigure.data.redis.RedisRepositoriesAutoConfiguration
this should work with properties files as well.
I like the fact that there is no need to change the application code to do that.
I add in myApp.java, after #SpringBootApplication
#EnableAutoConfiguration(exclude = {DataSourceAutoConfiguration.class, DataSourceTransactionManagerAutoConfiguration.class, HibernateJpaAutoConfiguration.class})
And changed
#SpringBootApplication => #Configuration
So, I have this in my main class (myApp.java)
package br.com.company.project.app;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration;
import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration;
import org.springframework.context.annotation.Configuration;
#Configuration
#EnableAutoConfiguration(exclude = {DataSourceAutoConfiguration.class, DataSourceTransactionManagerAutoConfiguration.class, HibernateJpaAutoConfiguration.class})
public class SomeApplication {
public static void main(String[] args) {
SpringApplication.run(SomeApplication.class, args);
}
}
And work for me! =)
In my case the spring-boot-starter-jpa dependency was being loaded from other dependency. I did this to disable the DataSource:
Check the dependency tree with mvn dependency:tree
[INFO] com.backend.app:crud-manager:jar:0.1-SNAPSHOT
[INFO] +- ...
[INFO] \- com.backend.app:crud-libraries:jar:0.1-SNAPSHOT:compile
[INFO] +- org.springframework.boot:spring-boot-starter.data-jpa:jar:2.1.6.RELEASE:compile
[INFO] +- ....
There was a sub-dependency. Add an exclusion
<dependency>
<groupId>com.backend.app</groupId>
<artifactId>crud-libraries</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
<exclusion>
</exclusions>
</dependency>
Exclude DataSourceAutoConfiguration.class in the Application file
import org.springframework.boot.autoconfigure.jdbc. DataSourceAutoConfiguration;
// add exclude
#SpringBootApplication(exclude = DataSourceAutoConfiguration.class)
public class ...
Ensure there is no spring-boot-starter-jpa in pom.xml
** Apart, in case you also need to make it work with spring-boot-starter-batch
In the BatchConfig file:
// add extends DefaultBatchConfig
public class BatchConfig extends DefaultBatchConfig {
//add override
#Override
public void setDataSource(DataSource dataSource) {}
I was getting this error even if I did all the solutions mentioned above.
by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'dataSource' defined in class path resource [org/springframework/boot/autoconfigure/jdbc/DataSourceConfig ...
At some point when i look up the POM there was this dependency in it
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
And the Pojo class had the following imports
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
Which clearly shows the application was expecting a datasource.
What I did was I removed the JPA dependency from pom and replaced the imports for the pojo with the following once
import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.Document;
Finally I got SUCCESSFUL build. Check it out you might have run into the same problem
Also if you use Spring Actuator org.springframework.boot.actuate.autoconfigure.jdbc.DataSourceHealthContributorAutoConfiguration might be initializing DataSource as well.
By default in Spring, all the defined beans, and their dependencies, are created when the application context is created.
In contrast, when we configure a bean with lazy initialization, the bean will only be created, and its dependencies injected, once they're needed.
spring:
main:
lazy-initialization: true
jpa:
properties:
hibernate: # lazy-initialization works with this dialect property to avoid run issues if DB is Down
dialect: org.hibernate.dialect.Oracle10gDialect

Resources