Global variables And Application Variables Defining in Spring boot project - java

I am trying to develop micro service by using spring and spring boot. In my project , I am converting monolithic to service oriented architecture. Project contain 20 Micro services.I these I need to set application variables and global variables. I have confusions related to this , And I am adding those confusions here,
Is possible to declare my global variables in application.properties file? If not possible where I can define my global variables?
If I am using spring config server for global configuration, How I can import those properties conditionally to client project?
Can I set different property files for different profiles in config server , and conditionally import into client project for different profiles? Here each profile representing different regions in my case.

After My Exploration I find out Solution for this problem for loading global variables and application variables including database configuration. The best way we can use that is - spring cloud config server externalized configuration.
We can create a microservice for spring cloud config server. In config server we can create our variables and configuration in two ways.
Configurations from GIT Link reference
Using local file system / Environment variables.
Links To refer
https://cloud.spring.io/spring-cloud-config/single/spring-cloud-config.html
https://cloud.spring.io/spring-cloud-static/spring-cloud-config/1.3.3.RELEASE/multi/multi__spring_cloud_config_server.html
https://github.com/spring-cloud/spring-cloud-config
Here I followed using local file system.
Need to create Config folder under src/main/resources. And create different profiles by following naming convention,
db,properties , db-test.properties , db-prod.properties , db-dev.properties.
I created for example for different development environment. Like we can create any profiles for variables and configuration.
And add following in application.properties for config server
server.port=8888
spring.profiles.active=native
Add config server dependency in pom.xml file of config server,
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-server</artifactId>
</dependency>
Add the following into main application run class,
#SpringBootApplication
#EnableConfigServer
public class ConfigServerApplication {
public static void main(String[] args) {
SpringApplication.run(ConfigServerApplication.class, args);
}
}
And also create client microservice project by adding pom.xml dependency,
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
Add following line in application.properties file for setting client to receive configuration from server,
server.port=8080
spring.application.name=db
spring.cloud.config.uri=localhost:8888
Finally run your client project by specifying profile ,
java -jar -Dsping.profiles.active=<profile> <jar_name>.jar
Thanks In advance

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

How can a library module of a Spring application add additional configuration to the application's `application.yml`?

I have a Spring Boot application built with Maven which uses JDBC. The application.yml file has
spring:
application:
(stuff)
datasource:
url: jdbc:informix-sqli://......
driver-class-name: com.informix.jdbc.IfxDriver
I want to move the JDBC specific parts into a library so now the app/src/main/resources/application.yml only contains
spring:
application:
(stuff)
and the datasource configuration parameters need to live in the library repository. I tried creating lib/src/main/resources/application.yml with
spring:
datasource:
url: jdbc:informix-sqli://......
driver-class-name: com.informix.jdbc.IfxDriver
hoping that both the yml files would be picked up and merged when Spring loads up. Apparently not.
The library and application build fine, but when I run it
***************************
APPLICATION FAILED TO START
***************************
Description:
Failed to configure a DataSource: 'url' attribute is not specified and no embedded datasource could be configured.
How can I get the configuration in the library to be merged into the application.yml configuration in the application?
I have always found "merging" of external configuration from sub-modules with spring-boot to be problematic at worst, confusing at best. I now organize all external configuration using one of two approaches. But first, there are multiple ways to specify external configuration that you should be aware of:
Spring Boot and multiple external configuration files
Starting Spring Application by merging yml files
https://docs.spring.io/spring-boot/docs/current/reference/html/spring-boot-features.html#boot-features-external-config
I previously would specify multiple locations and that sort-of worked. But, I now typically use one of two approaches to avoid confusion:
I use profiles and specify multiple profiles at runtime when launching the spring boot app. i.e. Multiple profiles like "shared-common, shared-jdbc, deploy-prod" which will load "application-shared-jdbc.yml" out the sub-module.
or
I create a module that contains nothing but configuration files that get used by all related modules, often with multiple profiles for different configuration scenarios. All other modules (executable and libraries) depend on this shared configuration module.
AFAICT, spring-boot's external configuration handling not setup ideally for having standalone submodule configuration. It's more oriented around the notion that configuration belongs to runtime/executable modules, not libraries.
you can use #PropertySource. you have to implement your own PropertySourceFactory
if your props is in yaml format. then define it in the PropertySource
#PropertySource(value = ResourceUtils.CLASSPATH_URL_PREFIX
+ "application.yml", factory = Factory.class)

Spring Boot App not picking up application.properties from dependent jar

I have two spring boot apps. The first is an API library that's pulled into the second (a web application) as a dependent jar.
The first, is an API library that houses functions to create "cases" in an IBM solution. It's a standalone type jar that has a service class that exposes methods like getCaseXMLForDocId(String docId) or createCaseForAgreementNumber(String agreementNumber)
The first library called CaseInvocationAPI has an application.properties file which has several properties. For example:
caseinvocation.query.fetchNonProcessedCaseXml=SELECT Id, CaptureSource, AgreementNumber, CaptureSourceID FROM CaseInvocation WHERE ProcessIndicator IN (0, 2)
The service class has a method which makes a query, grabbing that query string from a member variable that's populated with a property from the application.properties file:
#Value("${caseinvocation.query.fetchNonProcessedCaseXml}")
private String selectNonProcessedQueryString;
The second SpringBoot app is a webapplication that has REST controllers. These controllers expose endpoints that call the CaseInvocationAPI library, specifically the CaseInvocationService class.
The problem I am having is that when the SpringBoot WEBAPPLICATION starts up, the context configuration blows up with the following error:
Caused by: java.lang.IllegalArgumentException: Could not resolve placeholder 'caseinvocation.query.fetchNonProcessedCaseXml' in string value "${caseinvocation.query.fetchNonProcessedCaseXml}"
at org.springframework.util.PropertyPlaceholderHelper.parseStringValue(PropertyPlaceholderHelper.java:174)
at org.springframework.util.PropertyPlaceholderHelper.replacePlaceholders(PropertyPlaceholderHelper.java:126)
at org.springframework.core.env.AbstractPropertyResolver.doResolvePlaceholders(AbstractPropertyResolver.java:219)
at org.springframework.core.env.AbstractPropertyResolver.resolveRequiredPlaceholders(AbstractPropertyResolver.java:193)
at org.springframework.context.support.PropertySourcesPlaceholderConfigurer$2.resolveStringValue(PropertySourcesPlaceholderConfigurer.java:172)
at org.springframework.beans.factory.support.AbstractBeanFactory.resolveEmbeddedValue(AbstractBeanFactory.java:813)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1039)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1019)
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:566)
at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:88)
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:349)
... 45 common frames omitted
It appears that when the WebApp starts up, when it's trying to build the classes from the dependent jar, those properties are not being found.
I didn't think I had to copy each and every property out of the dependent jar application.properties file into an application.properties file in the Webapp project.
Why isn't the WebApp project (CaseInvocationWebApp) picking up the application.properties file from the dependent jar file (CaseInvocationAPI)?
I checked the compiled jar file (CaseInvocationAPI) and the application.properties file is there in the jar.
Looks like the problem was related to the fact that both the child jar and the webapp have application.properties files. I wasn't aware that the parent WebApp application.properties sort of overwrites the others (ignoring all others really).
Special thanks to Paschoal for his response.
You can see details on the answer here:
Adding multiple application.properties files
There are 3 ways (that I can think of) you can approach this:
The dependency, API library, should not have an application.properties since it's a library and not an executable Spring boot application in itself. You only define the properties in your web application's application.properties, even for the API library.
But, here the assumption is that you have access to the API library jar.
You can redefine all the properties in web application's application.properties essentially overriding them.
Explicitly configure the Spring boot application to use both the application.properties files, each for different set of properties.
Caveat: The file names must be different, as config location is classpath for both.
#SpringBootApplication
public class WebApplication {
public static void main(String[] args) {
SpringApplication app = new SpringApplicationBuilder(WebApplication.class)
.properties("spring.config.location=classpath:api-application.properties,classpath:application.properties")
app.run(args);
}
}

Spring boot configuration in a multi-Module maven project

I'm having a problem properly setting up spring boot for my multi-module maven project.
There is a module "api" that uses another module "core". Api has an application.properties file that contains spring.mail.host=xxx. According to the spring boot documentation this provides you with a default implementation of the JavaMailSender interface, ready to be autowired.
However the class that is responsible for sending out the e-mails resides in the "core" package. When I try to build that module the build fails because no implementation of JavaMailSender can be found.
My guess then was that the mailing config should reside in "core" in a separate application.properties. I created that and moved the spring.mail.host property from the "api" to the "core" property file.
This time the core module builds successfully, but "api" fails to build because of the same exception, so I think I just moved the problem.
I don't understand the required structure for handling this type of situations well enough so I was wondering what the correct way is for having a "core" module containing all the correct configuration for sending mails and having other modules use the mailing code and config that resides in it.
I found the answer in another stack overflow question: How to add multiple application.properties files in spring-boot?
It turns out there can only be 1 application.properties file in the final jar that spring boot creates. To have multiple files you have to rename one of the files to something custom. I named the properties of the core module "core-application.properties".
Then in the API module I added this to the spring boot application class:
#SpringBootApplication
#PropertySource(value = {"core-application.properties", "application.properties"})
Doing this I can correctly use the base properties file and overwrite them in the more specific modules. Also you can still create profile-specific properties file (core-application-production.properties) with this setup, no need to add those to the propertysource manually). Note that #PropertySource does not work for yaml configuration files at this moment.
there is one effective application.properties per project. you just keep 2 properties file for a success build.
when api module use core module, the application.properties in core module is overwrite by api.
Your API's pom.xml must has dependency of CORE module.
the solution is to define properties files as a value of #PropertiesSource in Starter class.
but it is beter to put "classpath:" behind the properties files.
for example in Intellij idea after adding the "classpatch:" word berhind the files name, values become to link. like this:
#SpringBootApplication
#PropertySource(value = {"classpath:core-application.properties", "classpath:application.properties"})
I hope to helped you.

Categories

Resources