Spring Framework PropertySource based on Profile - java

I have a Spring Boot multi-module maven project. I want my library module to handle its own properties.
So, in the library module:
src/java/resources/module-name/application.properties
src/java/resources/module-name/application-dev.properties
src/java/resources/module-name/application-prod.properties
I have a #Configuration class in that module with:
#PropertySource("classpath://module-name/application-dev.properties")
Obviously, this will only load the dev properties.
2 Questions:
1) How do I factor in #Profile in here so I don't have to create multiple configuration classes, each with its own #Profile. Is there a way to combine the annotations or parameterize them with something like application-${spring.active.profile}.properties?
2) How do I achieve the same behavior vis-a-vis application.properties file as I would have out of the box if these files were in the root of the classpath and picked up automatically by Spring? In other words, I'd like to place all the common properties into application.properties file and only the profile specific ones into application-dev.properties or application-prod.properties ones.

Related

Inject #Value inside into #PropertySource in spring boot

I have two application property profiles dev and prod. I set the profile active in my application properties file as spring.profiles.active=dev
I want to dynamic load of my classpath properties file according to the active profile. so I want to inject the #Value annotation into my classpath variable as below:
#Configuration
#PropertySource({"classpath:application-#Value('${spring.profiles.active:}').properties"})
is it possible to do that??
You need to have one file application.properties where you have to specify the profile like this spring.profiles.active=dev
And than create dedicated files for each profile where you have specific configs.
application-dev.properties
application-uat.propertiea
Than you can use Value annotation and it will be picked automatically.
See this:https://dzone.com/articles/spring-boot-profiles-1

Overriden application.yml in multi-module Spring Boot app

There is a Spring Boot 2 app with such a structure:
parent-module
module-1
src
main
java
resources
- application.yml
module-2
src
main
java
resources
- application.yml
Also, module-1 depends on module-2, specified in pom.xml dependencies section.
The problem is that when I specify some properties in module-2's application.yml - they are not visible in main module-1's components (via #Value annotation).
As was answered here seems like module-1's application.yml overrides module-2's application.yml. There is a workaround - if I use name application.yaml in module-2 everything works fine, but I'm going to add more modules and, finally, it's dirty hack.
What I'm doing wrong? Should such an hierarchy of property files specified somehow?
I will be happy to provide more details if it's needed.
Thank you!
Spring Boot is a runtime framework. I understand that your modules are not spring-boot applications by themselves (you can't make a dependency on a spring boot application packaged with spring boot maven plugin, because it produces an artifact that is not really a JAR from the Java's standpoint although it does have *.jar extension).
If so, they're probably regular jars. So you should have a "special" module that assembles the application. This special module lists both 'module1' and 'module2' in <dependency> section and should contain a definition of spring-boot-maven-plugin in its build section (assuming you're using maven). But if so you shouldn't really have more than one application.yml - it will be misleading. Instead, put the application.yml to the src/main/resources of that "special" module.
If you really have to for whatever reason work with multiple application.yaml files, make sure you've read this thread
I know, this is already a well-aged post.
I just came accross the same issue and the best solution I found was to import the module-specific configurations with the spring.config.import directive as described here.
In this case you still have your module specific configuration in property or yaml files within that specific module and do not have too much unwanted dependencies in your project setup.
application.yml is, as the name indicates, an application-level file, not a module-level file.
It is the build script that assembles the final application, e.g. the .war file, that needs to include a application.yml file, if any.
If modules need properties, and cannot rely on the defaults, e.g. using the : syntax in #Value("${prop.name:default}"), they need to provide a module-level property file using #PropertySource("classpath:/path/to/module-2.properties").
Note: By default, #PropertySource doesn't load YAML files (see official documentation), but Spring Boot can be enhanced to support it. See #PropertySource with YAML Files in Spring Boot | Bealdung.
Alternative: Have the application-level build script (the one building the .war file) merge multiple module-level build scripts into a unified application.yml file.

How to externalize application.properties files in Spring Boot to e.g. external dependent JAR?

I have a simple Maven module (not a Spring Boot application) in which I have placed my application.properties file.
I have 6-7 Spring Boot applications and I don't want to have an application.properties file in each and every application directory. I prefer it, if it is at one single place (external Maven module).
I am adding the maven module as a dependency in each of those Spring Boot application poms.
But, when I run those applications, it is not able to auto-detect the application.properties file because it is coming from a dependent jar not present physically in each of their application directories.
Is there any way to make this possible? I would like to avoid having properties files in 6-7 different locations, because that becomes tough to manage and handle.
Thank you in advance!
Consider using Spring Cloud Config that provides server and client-side support for externalized configuration in a distributed system. It requires some small effort, but it is very useful in long term. Config server manages configuration files (.properties or .yml), you can still use different config per profile (e.g. application-test.properties, application-prod.properties etc.). Your application has a higher priority, so you can always override properties coming from config server if needed. Another cool feature is that config server can utilize Git repository, so you can easily version all your configuration files. It also supports encryption - any fragile data can be encrypted so only your application knows how to decrypt it.
Config server
Config server is nothing else than a simple Spring Boot application that can be implemented as:
#SpringBootApplication
#EnableConfigServer
public class ConfigServer {
public static void main(String[] args) {
SpringApplication.run(ConfigServer.class, args);
}
}
with simple application.properties file included:
server.port: 8888
spring.cloud.config.server.git.uri: file://${user.home}/config-repo
with dependency in pom.xml
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-server</artifactId>
</dependency>
Config client
On client side you add a dependency to your pom.xml (or its equivalent in build.gradle if you use Gradle):
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-client</artifactId>
</dependency>
and all you have to do is add a URL to config server to your application.properties (or application.yml if you use YAML insted):
spring.cloud.config.uri: http://myconfigserver.com
Config files structure
Now let's say you have set up Git repository for your configuration files. Let's assume that your applications are named like horus, venus, mercury etc. and you have 3 different profiles: dev, test and prod. You also have some configuration that is common for all applications. In this case your configuration files structure would look like this (I will use properties files here but it applies to YAML as well):
application.properties - common config for all apps no matter what profile they use
application-dev.properties - common config for all apps running with dev profile
application-test.properties - common config for all apps running with test profile
application-prod.properties - common config for all apps running with prod profile
horus.properties - horus app config for, common for all profiles
horus-dev.properties - horus app config for dev profile only
horus-test.properties - horus app config for test profile only
horus-prod.properties - horus app config for prod profile only
etc.
There are some additional options that can be set (like encryption, connection strategy (fail fast or ignore) etc.), everything is well described and documented in official documentation https://cloud.spring.io/spring-cloud-config/ Hope it helps you making a good choice for managing your configuration in distributed application environment. Config server is a solution that was invented to solve this problem.
While Szymon Stepniak's answer certainly is a "by-the-book" of Spring Boot answer, I understand your situation, and even tried to do what you try to do by myself. Indeed, you can't define application.properties in other "external modules".
Here is how I've solved it:
Create a configuration in the "common" module
Create a property file in src/main/resources. It shouldn't be named application properties, It's better to provide a unique name for it (at least this is how I've done it, so let's assume that the file is called application-common.properties)
Use #PropertySources annotation to define a property file and load it with configuration.
Here is an example:
package com.myapp.common;
#Configuration
#PropertySources({
#PropertySource("classpath:application-common.properties")
})
public class MyConfiguration {
// you don't really have to define beans
}
Now if you want this configuration to load automatically only because the dependency is defined in your spring boot module of your build system, I've found the best to utilize spring factories:
Create the file src/main/resources/META-INF/spring.factories
Place the following into this file:
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.myapp.common.MyConfiguration

Spring-boot > implicitly auto register a 3rd party bean

This may be an impossible task, but here goes...
Is it possible to register a spring bean, by (ONLY) adding a jar to the classpath of a spring-boot application?
Scenario: I would like to create a non-intrusive plugin jar, which when imported into a spring-boot project's classpath, will automatically be picked up and provide a service (e.g. via a RestController).
Constraints
I don't want to change or reconfigure the existing spring-boot application (i.e. no additional scan paths or bean config).
I don't have any knowledge of the target spring-boot application's package structure/scan paths.
I guess I was hoping that by default Spring scan's its own package structure (i.e. org.springframework.** looking for the presence of database libs, etc) and I could piggy-back off that - I haven't had any luck (so far).
I've setup an example project in github, to further clarify/illustrate my example and attempts.
** Solution Addendum **
This bit that got it working, was to add the following file, which points to an #Configuration config file...
plugin-poc\src\main\resources\META-INF\spring.factories
org.springframework.boot.autoconfigure.EnableAutoConfiguration=org.thirdpartyplugin.PluginConfiguration
I think in such cases you would try to add a spring auto configuration that is annotated with #ConditionalOnClass to be only evaluated if the given class is on the classpath. This class can register the bean and would just be evaluated if the conditional evaluates to true
Here is the relevant part of the spring boot documentation : Creating your own auto-configuration

JAVA SPRING - Using Maven, steps to create 2 war file (quality & production)

Can anyone please help me to create 2 war files using maven, java spring?
Requirement: Need 4 war file
For that 1st create 2 war file
(make another 2 copy from this with different name for oauth)
database name only diff between staging & production war
staging (http://10.19:3006/imdesk_imapi_staging)-sql datasource- for staging
1)war - api
2)oauth staging war - copy
production (http://10.19:3006/imdesk_imapi_production)-sql datasource for ****production****
1)api - war
2)oauth war - copy
work with maven profiles
http://maven.apache.org/guides/introduction/introduction-to-profiles.html
so you can create different artifacts for different stages
I see two paths you could take to solve the issue:
1. Use maven profiles.
http://maven.apache.org/guides/introduction/introduction-to-profiles.html
How can a profile be triggered? How does this vary according to the type of profile being used?
A profile can be triggered/activated in several ways:
Explicitly
Through Maven settings
Based on environment variables
OS settings
Present or missing files
Details on profile activation
Profiles can be explicitly specified using the -P CLI option.
This option takes an argument that is a comma-delimited list of profile-ids to use. When this option is specified, the profile(s) specified in the option argument will be activated in addition to any profiles which are activated by their activation configuration or the section in settings.xml.
mvn groupId:artifactId:goal -P profile-1,profile-2
2. Use Spring profiles.
https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-profiles.html
Spring Profiles provide a way to segregate parts of your application configuration and make it only available in certain environments. Any #Component or #Configuration can be marked with #Profile to limit when it is loaded:
`#Configuration
#Profile("production")
public class ProductionConfiguration {
// ...
}
In the normal Spring way, you can use a spring.profiles.active Environment property to specify which profiles are active. You can specify the property in any of the usual ways, for example you could include it in your application.properties:
spring.profiles.active=dev,hsqldb
or specify on the command line using the switch --spring.profiles.active=dev,hsqldb

Categories