Spring externalize configuration yml - java

I am trying to configure the spring-boot application with yml and properties. I might have made mistakes at multiple places :)
I run my application as below with following contents :
java -jar /opt/elast-search-0.0.1-SNAPSHOT.jar --spring.config.location=. --spring.config.name=elast.properties,ere.yml
My YAML file looks like :
log:
count: 1
searchText: someText
services:
- um
- sa
minutesTime: 1
count: 2
searchText: someMoreText
services:
- um2
- sa2
minutesTime: 2
Without the elast.properties file and the second bean content (i.e. from count to the minutesTime section in yaml) I see the yml is loading and I am running it with :
java -jar elast-search-0.0.1-SNAPSHOT.jar --spring.config.location=ere.yml
I am running multiple properties file because I want to have a default configuration as well and the module is still evolving. I have #Autowired the class in the spring boot application.
#Configuration
#EnableConfigurationProperties
#ConfigurationProperties(prefix = "log")
public class LogRule {
private int count;
private String searchText;
private String[] services;
private int minutesTime;
}
I want to read all YAML configuration as a list.
I want to read the configuration file if the file is changed or at regular intervals.

Related

Is there a way to get list of loaded properties file in SpringBoot application?

I'm facing an issue on only one platform when I'm trying to execute mvn clean install. As part of the build we compile multiple component and last we execute functional testing using wiremock. It is supposed to pick specific configuration from function testing profile and default properties should be picked from application.properties file. But for some reason same code isn't able to find the properties mentioned in these file. So, just wondering if somehow, if I can get the list of properties files being loaded during wiremock ? This will give some clue on why isn't expected properties files are being picked ?
All properties files are located inside :
src/main/resources
And, following from test class.
#ContextConfiguration(classes = SampleFTConfiguration.class)
public class SampleControllerTest{
//test method
}
#ComponentScan("com.xxx.xxx.xxx.ft")
#PropertySource("classpath:application-test.properties")
public class SampleFTConfiguration{
}
Note : I'm not expecting anyone to fix the issue, all I wanted to know, if we can get the name of loaded property files ?
After searching and trying out for a while, looks like ConfigurableEnvironment is what you're trying to find.
The code is pretty simple. However I think it's better to debug and check the configurableEnvironment value directly, so you can adjust the code to your needs (remove filter name, etc).
#Autowired
private ConfigurableEnvironment configurableEnvironment;
#Test
public void getProperties() {
Map<String, Object> mapOfProperties = configurableEnvironment.getPropertySources()
.stream()
.filter(propertySource -> propertySource.getName()
.contains("application-test.properties"))
.collect(Collectors.toMap(PropertySource::getName, PropertySource::getSource));
mapOfProperties.values()
.forEach(System.out::println);
}
the code will printed out
{properties-one=value-for-properties-one,
properties-two=value-for-properties-two}
with my application-test.properties value
properties-one=value-for-properties-one
properties-two=value-for-properties-two
https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/core/env/ConfigurableEnvironment.html
Ok, following the test definition please make sure that:
You should run the test with spring runner (spring extension if you're on JUnit5). So you should place the annotation #RunWith(SpringRunner.class) (or #ExtendsWith(SpringExtension.class) for junit 5)
The property source you're using is application-test.properties. You've said that the properties file is located in src/main/resources but the file name probably implies that it should reside in src/test/resources
To troubleshoot context configuration on app startup (for those who don't have an access to app sources) you can add
logging:
level:
org.springframework.boot.context.config: trace
to your application.yml to get filenames:
2022-10-26 13:29:45.977 TRACE [,,] 16522 --- [main] o.s.b.context.config.ConfigDataLoaders : Loading file [config/application-app.
yml] using loader org.springframework.boot.context.config.StandardConfigDataLoader
2022-10-26 13:29:45.977 TRACE [,,] 16522 --- [main] o.s.b.context.config.ConfigDataLoaders : Loading file [config/application-ppe.
yml] using loader org.springframework.boot.context.config.StandardConfigDataLoader
Adding org.springframework.boot.context.properties: trace doesn't help much though. Some user-defined properties get logged, however others don't.

Spring - yaml and .properties configurations

i've been working with Spring for some time and have a question regarding the very common configuration properties files (like the common application.properties that comes with every spring boot app you initialize). Recently, i also found that configurations like this can be done in yaml files. I have two questions:
When in a application.properties file, we write something like:
# application.properties
spring.debug = true
some-random-value = 15
does this mean that these values will be injected in the application context?
When we write something like:
# application.properties
spring.debug = true
does this mean, that somewhere, there is some class, that has an attribute that looks something like this? -->
#Component
class SomeClass{
#Value("spring.debug")
boolean shouldIRunInDebugMode;
...
}
2.a. If the answer to question 2 is yes, then how can I, looking at something like this:
# application.properties
spring.debug = true
find that class that is expecting that value. The same would apply to if i was looking at something like:
# application.yaml
someThidPartyLibraryName:
shouldWeLog: true
If i see a yaml configuration file, just looking at all the configuration there usually is not enough for me to know what is happening. How can i find the class that is being affected by this configuration, so that i can better understand what this config is doing?
Thank you!
The response is generally yes. If you declare a property in the application.properties or application.yaml is mainly, because you would use it later in the code, for example injecting in some bean with the support of #Value annotation. However, there are also many built-in properties (let's say for example server.port), which you usually don't have to declare and therefore you won't see explicitly in the code. Use an IDE to search the configuration properties and the manual to check the preconfigured ones in case of need.
Your understanding regarding spring value injections from application.properties is correct. #2 - is Yes. Any property from application.properties can be injected to any java class as #Value.
Regarding #2.a - Yaml is just another format on how you organize your variable hierarchy by indentations. That's a superset to the JSON structure.
For example,
in application.properties file you can add something like this
myapp.db.url=<dburl>
myapp.db.username=<dbuser>
myapp.db.password=<dbpassword>
the same can be represented in Yaml in a much efficient manner as below
myapp:
db:
url:<dburl>
username:<dbuser>
password:<dbpassword>
And in either case, for your Jave file you can inject as
#Value("myapp.db.url"
private String dbUrl;
Properties defined in yaml or a properties file may be accessed using the #Value annotation to inject, or using a #ConfigurationProperties class - see https://docs.spring.io/spring-boot/docs/current/reference/html/spring-boot-features.html#boot-features-external-config-typesafe-configuration-properties for complete details.
Finding the property usage is supported by some IDEs - IntelliJ allows you to click through. Otherwise it's a search through the source. For #ConfigurationProperties, once you find the class then just look for code that calls its accessor methods.
Properties files and yaml files are used in Spring Boot for configurations. The main difference between the two is yaml provides structuring/grouping of configurations where as Properties are usually flat and may be repeating the same information:
For example;
Properties file
server.port = 8080
server.host = localhost
yaml file
server:
port: 8080
host: localhost
But in a Spring Boot AutoConfiguration class regardless of yaml or Properties used, a following looking ConfigurationProperties class will be used which will map server.port and server.host
#ConfigurationProperties(prefix = "server")
public class ServerConfiguration {
private int port;
private String host;
}
#Configuration
#EnableConfigurationProperties(ServerConfiguration.class)
public class ServerAutoConfiguration {
}
Hope this answers your questions.

Spring boot application configuration question

I have following structure of my application
----
|
|____SpringBootApplicationA
|
|
|___module-1
|___module-2
Each module has its own configuration, For example, module-1 is library that talks to mysql, it has its configuration (connection string, username, password,etc...)
Now I want to represent this configuration in the form of Java POJO in module-1. application.yml and a bean that read configuration and sets the values.
For example
class Module1Config {
private String key1;
private String key2;
// getters & setters
}
application.yml at module-1
key1: val1
key2: val2
now as a consumer of module-1, SpringBootApplicationA will receive module-1's configuration which is what set as default by module-1.
On the consumer side it will have application configuration like this
someKey1: someVal1
someKey2: someVal2
module-1:
key1: overrideVal1
and when initialization happens of module-1's beans, I want the values to be seen as
key1: overrideVal1
key2: val2
How to configure spring boot to respect default values and override them ?
Edit
class AppConfig {
private String key1;
private int key2;
private Module1Config conf;
// getters + setters
}
This is my example application config, as you can see it has some specific to application config and other configs it is leveraging from other modules.
I want conf object to get assigned default set of value from module1 and then whatever application has specified as an override
Spring boot by default loads application.yml file
from src/main/resources
You can declare another application.yml file in
config folder of root path and configuration from
config folder will override configuration from src/main/resources
Config locations are searched in reverse order. By default, the configured locations are classpath:/,classpath:/config/,file:./,file:./config/. The resulting search order is the following:
file:./config/
file:./
classpath:/config/
classpath:/
Here is link from official documentation:
https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-external-config.html
I think it’s helpful

Spring Boot can't find profile-specific properties files

I am following Spring documentation to use profile specific property files for my SpringBoot app. I have 2 property files under src/main/resources : datasource.properties for local development and datasource-prod.properties for server datasource config.
This is my DataSourceConfiguration.java config class :
#Configuration
#PropertySource("classpath:datasource-{profile}.properties")
#Slf4j
public class DataSourceConfiguration {
#Value("${flad.datasource.driver}")
private String dataSourceDriverClassName;
#Value("${flad.datasource.url}")
private String dataSourceUrl;
#Value("${flad.datasource.username}")
private String dataSourceUsername;
#Value("${flad.datasource.password}")
private String dataSourcePassword;
#Bean
public DataSource getDataBase(){
log.info("Datasource URL = {}", dataSourceUrl);
return DataSourceBuilder
.create()
.driverClassName(dataSourceDriverClassName)
.url(dataSourceUrl)
.username(dataSourceUsername)
.password(dataSourcePassword)
.build();
}
}
When I launch my SpringBootApplication main class I get the following error whether I use -Dspring.profiles.active=prod or not :
17:05:49.008 [restartedMain] ERROR org.springframework.boot.SpringApplication - Application run failed
org.springframework.beans.factory.BeanDefinitionStoreException: Failed to process import candidates for configuration class [fr.payet.flad.core.config.CoreConfig]; nested exception is java.io.FileNotFoundException: class path resource [datasource-{profile}.properties] cannot be opened because it does not exist
The solution that I found is to rename my property files datasource-local.properties and datasource-prod.properties, use #PropertySource this way #PropertySource("classpath:datasource-${profile}.properties") and when I launch my SpringBoot app I use -Dprofile=local as VM options

Configure Multiple Database on Spring-Boot with JPA and Hibernate Web Application

I have ONE spring boot (1.5.4.RELEASE) project using java 8 deployed on AWS HPC. This project architect scope works for Spring Web Application(Website), Rest API Services(Mobile Developer) & Account Administration for Company.
So there is 3 different respective Database like (2-SQL Server & 1-MySQL).
Here on stack-overflow, I'm posting my question for find a best way to implementation this Spring-Boot Project by help of talented stack-overflow users.
Here is my configure properties files.
application.properties
#For Public Website
spring.datasource.clone.web.driver = com.microsoft.sqlserver.jdbc.SQLServerDriver
spring.datasource.clone.web.url = jdbc:sqlserver://127.0.0.01\\dbo:1433;databaseName=PROD_WEB;
# Username and password
spring.datasource.web.username = web
spring.datasource.web.password = ED5FLW64ZU976Q36
#For Rest API
spring.datasource.clone.url = jdbc:mysql://localhost:3306/PROD_REST;
# Username and password
spring.datasource.clone.username = rest
spring.datasource.clone.password = Firewall77#
#For Account Administration for Company Users
spring.datasource.admin.url = jdbc:sqlserver://127.0.0.01\\dbo:1433;databaseName=PROD_ADMIN;
# Username and password
spring.datasource.admin.username = admin
spring.datasource.admin.password = Firewall77#
# Backup & Cron Policy
...
I would greatly appreciate for some very good suggestion to implement it. your knowledge on this subject would help me, Thanks.
You need to implement two different beans, one for each datasource and make them take the corresponding configuration properties respectively:
First bean will be responsible for the first datasource configuration, and should be daclared as primary datasource with #Primary, so it can be setup as the main datasource for the project.
The second bean will configure the second datasource.
This is how they should be implemented in Spring:
#Bean
#Primary
#ConfigurationProperties(prefix="spring.datasource.web")
public DataSource primaryDataSource() {
return DataSourceBuilder.create().build();
}
#Bean
#ConfigurationProperties(prefix="spring.datasource.rest")
public DataSource secondaryDataSource() {
return DataSourceBuilder.create().build();
}
Here's how should be your application.properties configured, to take these two beans configuration into account:
#For Public Website
spring.datasource.web.driver = com.microsoft.sqlserver.jdbc.SQLServerDriver
spring.datasource.web.url = jdbc:sqlserver://127.0.0.01\\dbo:1433;databaseName= PROD_WEB;
# Username and password
spring.datasource.web.username = web
spring.datasource.web.password = ED5FLW64ZU976Q36
#For Rest API
spring.datasource.rest.driver = com.microsoft.sqlserver.jdbc.SQLServerDriver
spring.datasource.rest.url = jdbc:mysql://localhost:3306/PROD_REST;
# Username and password
spring.datasource.rest.username = rest
spring.datasource.rest.password = Firewall77#
Note:
I changed the configuration properties here so they can be differentiated between web and rest datasources:
Properties starting with spring.datasource.web will be dedicated to configure the first datasource.
Properties starting with spring.datasource.rest will be dedicated to configure the second datasource.
try to use DataSource configuration specified at Configuration for each data sources for more help check this Using multiple datasources with Spring Boot and Spring Data

Categories