Select spring boot xml configuration at runtime - java

I have to run a legacy spring boot (2.1.8) app
SpringApplication.run(MyApplication.class, args);
with XML beans config which must be selected at runtime from the src/main/resources dir:
a/config.xml
or
b/config.xml
based on an env variable with the respective value a or b. Is there a way to load XML config like this?

Have you looked into Spring Profiles; this might get you where you want to be.

Related

Liquibase change-log in Spring Boot

I'm trying to figure out how the project works.
It uses Liquibase:
The problem is that the .yaml file is not in the classpath folder so it's not accessible.
Error:
How to let Spring Boot know where is the change-log?
Use property name as
spring.liquibase.changeLog
not
liquibase.changeLog

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)

#Value inside class file in third party jar spring boot

I am working on a migrating an old Spring XML config-based app to Spring Boot and there are third party jars which have #Value("$ properties referenced in them. I tried loading a custom property file placed under /resources in the new Spring Boot workspace and loading it with #PropertySource("classpath:file") but during the Spring Boot run the property does not seem to be loaded and get this below error:
Could not resolve placeholder 'com.example.propertyName' in value "${com.example.propertyName}"
at org.springframework.util.PropertyPlaceholderHelper.parseStringValue(PropertyPlaceholderHelper.java:178)
~[spring-core-5.2.2.RELEASE.jar:5.2.2.RELEASE]
You can bind the properties values using annotation #Value then mentioned the key on it.
you can follow the below link for end to end example
click

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

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