I am writing a spring mvc application. I want to make use of spring profiles' features. I want to have a single application.properties with common and profile specific properties. I also want to have a set a default profile in the same file. How do i do this?
You could create an extra spring configuration class to dynamically return the properties based on the spring profile:
#Configuration
#PropertySource("classpath:application.properties")
public class QuotePropertyConfiguration {
#Inject
private Environment environment;
#Bean
public String getMySpecificProperty() {
return environment.getProperty("myprop." + Arrays.toString(env.getActiveProfiles()) + ".thing");
}
}
That will return you e.g. myprop.dev.thing, myprop.test.thing, myprop.prod.thing etc. depending on the active spring profiles.
Alternatively you can also do this with multiple application.properties files: From the spring documentation:
In addition to application.properties files, profile-specific
properties can also be defined using the naming convention
application-{profile}.properties. The Environment has a set of default
profiles (by default [default]) which are used if no active profiles
are set (i.e. if no profiles are explicitly activated then properties
from application-default.properties are loaded).
Related
I need to integrate my spring boot app with the AWS Secret manager to retrieve the DB credentials from it. It has to work only on prod environment.
This is what I did until now
<dependency>
<groupId>com.amazonaws</groupId>
<artifactId>aws-java-sdk-secretsmanager</artifactId>
<version>1.12.131</version>
</dependency>
...
SpringApplication application = new SpringApplication(MyApplication.class);
application.addListeners(new DatabasePropertiesListener());
application.run(args);
And my listener implements the
ApplicationListener<ApplicationPreparedEvent>
Is there any way to run my method inside that listener only on specific environment ( kind of feature flag) ? I need to say that this is to early to use variables from properties files.
Update:
When we have to decide before context creation (.i.e. ApplicationListener is no Component/Bean), then we (just mimic profiles) set:
# env: SET MY_FLAG=foo -> System.getenv("MY_FLAG")
# system: java -jar -Dmy.flag=foo myApp.jar -> System.getProperty("my.flag")
# cmd arg:
java -jar myApp.jar aws
..and issue it in our (spring boot) main method like:
if("aws".equalsIgnoreCase(args[0])) // alternatively: System.get...
application.addListeners(new DatabasePropertiesListener());
Misunderstood answer
Sure we can: With spring (boot) core features!
Assuming our ApplicationListener is a "spring managed bean", we annotate it with:
#Component
#Profile("aws") // custom profile (name)
class MyApplicationListener implements ...
{ ... }
...this will not load this "bean" into our context, unless we define:
spring.profiles.acitve=aws,... # a comma separated list of profiles to activate
Profiles
Spring Profiles provide a way to segregate parts of your application configuration and make it be available only in certain environments. Any #Component (Or #Bean,#Service,#Repository...descendants), #Configuration or #ConfigurationProperties can be marked with #Profile to limit when it is loaded, as shown in the ...
... above example.
An advanced application of #Profile annotation:
with multiple profiles: "or"/"and" semantics
"not" (!) operator
#Profile("!local","aws") // (String[]: OR semantics) the annotated component/configuration/property will
// be loaded, when active profiles NOT contains "local" OR contains "aws"
// for AND semantics, we'd use (1 string): "!local & aws"
Activating Profile(s!)
spring.profiles.acitve can be set/added (like any spring property source) through several (14^^, precisely priorized) locations.
E.g. setting environment variable (5th lowest priority, but higher than application.properties (3rd lowest)):
SPRING_PROFILES_ACTIVE=aws
Or as a command line flag (when starting the application, 11th lowest/3rd highest priority):
java -jar myApp.jar --spring.profiles.active=aws,...
#comma separated list
For (spring) tests additionally exists an #ActiveProfiles annotation.
Remarks/Note
Deciding for profiles, we should ensure to "make it consistently" (not raising Nullpointer/BeaninitalizationExceptions ... with dependencies!;). If needed: Creating replacement/local/test (#Profile("!aws")) beans.
Activating a profile "xyz", automatically tries to load application-xyz.properties (with higher priority than application.properties (prio 3.1 - 3.4))...also in (spring-)cloud-config.
Not to forget: The default profile (activated by spring automatically, only when no explicit profile is activated).
Reference
For detailed documentation, please refer to:
Spring Boot - Externalized Configuration
Spring Boot - Profiles
Spring Environment Abstraction chapter
#Profile Javadoc
#ActiveProfiles Javadoc
Profile sample from Configuration Javadoc:
#Configuration classes may be marked with the #Profile annotation to indicate they should be processed only if a given profile or profiles are active:
#Profile("development")
#Configuration
public class EmbeddedDatabaseConfig {
#Bean
public DataSource dataSource() {
// instantiate, configure and return embedded DataSource
}
}
#Profile("production")
#Configuration
public class ProductionDatabaseConfig {
#Bean
public DataSource dataSource() {
// instantiate, configure and return production DataSource
}
}
Alternatively, you may also declare profile conditions at the #Bean method level — for example, for alternative bean variants within the same configuration class:
#Configuration
public class ProfileDatabaseConfig {
#Bean("dataSource")
#Profile("development")
public DataSource embeddedDatabase() { ... }
#Bean("dataSource")
#Profile("production")
public DataSource productionDatabase() { ... }
}
See the #Profile and Environment javadocs for further details.
Hi I am little bit confusign about using profiles in spring.My Scenario is I have a custom properties file.And It is values changes for each environment(dev,test,prod).I use same bean for each environment.But I want to change values for each environments.
In this property files all keys are same,only their values different.
mydev.properties
mytest.properties
myprod.properties
So How should I implement profile logic to my code in my scenario(Bean is same ,values are different)
//Here is my bean
#Component
#PropertySource("my.properties")
#ConfigurationProperties(prefix = "my")
public class MyProperties
{
....
I will add to 'spring.profiles.active' to my propertysource and is this enough?
//I plan to add spring.profiles.active
#Component
#PropertySource("my${spring.profiles.active}.properties")
#ConfigurationProperties(prefix = "my")
public class MyProperties
{
....
Please go through the Spring Boot Reference : Section 2.4. Profile-specific Properties
In addition to application.properties files, profile-specific
properties can also be defined by using the following naming
convention: application-{profile}.properties.
One need to define the profile specific properties in application-{profile}.properties
and declare the active profile
You can use a spring.profiles.active Environment property to specify
which profiles are active.
To answer your concern , the property value for the current active profile will be wired to the bean. Also note that
Profile-specific properties are loaded from the same locations as
standard application.properties, with profile-specific files always
overriding the non-specific ones, whether or not the profile-specific
files are inside or outside your packaged jar.
If several profiles are specified, a last-wins strategy applies. For
example, profiles specified by the spring.profiles.active property are
added after those configured through the SpringApplication API and
therefore take precedence.
In your case , the ideal way to define profile specific properties would be
application-dev.properties
application-test.properties
application-prod.properties
I want to read values from an active profile or can say active properties file.
I have three properties files
application-dev.properties
application-stage.properties
application-prod.properties
I have set an active profile to dev as follows
spring.profiles.active=dev
My application-dev.properties file has one entry that i want to read in my class.
application-dev.properties file
fix.connection.type=initiator
I tried reading this entry
#Configuration
#PropertySource("classpath:application-${spring.profiles.active}.properties")
#Component
public class AdaptorDestination {
#Value("${fix.connection.type}")
private String connectionType;
}
Exception
nested exception is java.lang.IllegalArgumentException: Could not resolve placeholder 'spring.profiles.active' in value "classpath:application-${spring.profiles.active}.properties"
Please help me out
You don't need to use #PropertySource annotation in order to load a property using #Value annotation.
Spring will load #Value property automatically from the current active profile.
Also, you don't need to specify ${spring.profiles.active} in the #PropertySource annotation as Spring always loads properties from the currently active profile by default.
Spring automatically resolves file name based on the profile suffix.
So you need only specify the base filename, e.g.:
#PropertySource("classpath:application.properties")
If the currently active profile is "dev" Spring will load properties at first from application.properties file and then override them with properties from application-dev.properties file.
You can read more here
You can use the annotation #Profile("profile-name") to determinate when to execute the method.
Spring Profiles
I am trying to maintain different Spring profiles for development and production, for which I have created a folder(web skeleton) on my desktop with my Spring Boot project, application-dev.properties and application-prod.properties.
However, I am unable to import the profile into my project. The code that I use to import it to my project is as follows.
#Configuration
#Profile("dev")
#PropertySource("file:///${user.home}/web skeleton/application-dev.properties")
public class DevelopmentConfig {
#Bean
public EmailService emailService(){
return new MockEmailService();
}
Can someone tell me if this is the right way to use PropertySource in Spring.
You can optionally define a custom source where we’re storing these properties, else the default location (classpath:application.properties) is looked up. So we now add the above annotations to the existing properties class:
#Configuration
#PropertySource("classpath:configprops.properties")
#ConfigurationProperties(prefix = "dev")
public class ConfigProperties {
// previous code
}
Now any properties defined in the property file that has the prefix dev and the same name as one of the properties are automatically assigned to this object.
#Simple properties
dev.host=mailer#mail.com
dev.port=9000
Check this
I have done this kind of configuration too
Just add below code in your configuration class
#PropertySource("classpath:application-${spring.profiles.active}.properties")
And this propery in application.properties
spring.profiles.active=dev
you can change it to prod and cert as per you need.
When defining properties in YAML for a Spring Boot 1.4 application, I have to use the main/resources/application.yaml file. So far, so good.
How can I override these dependencies using YAML depending for a specific profile when running or testing the application.
When using Spring Boot 1.4 (this applies for release 1.3 as well) YAML properties are always defined in the main/resources/application.yaml file. Depending on the chosen profile, the properties can be overridden by another set of properties.
To override these properties for test, a YAML file has to be given in the /test/resources/application-.yaml file, where is replaced by the active profile. It is important to see that the profile always has to be given, even when there is no active profile. In that case, the profile is ‘default’.
To override the properties when running the application, properties can be overridden for a specific profile using in a file called main/resources/application-.yaml file. Even for this situation, if no profile is given, the profile for the filename is ‘default’.
Example
The test class Spring14ApplicationTests.java for Spring Boot 1.4 has the following definition
#RunWith(SpringRunner.class)
#SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.MOCK)
public class Spring14ApplicationTests {
…
}
For Spring Boot 1.3, the same file has the following definition
#RunWith(SpringJUnit4ClassRunner.class)
#SpringApplicationConfiguration(classes=SpringDb14Application.class)
#WebAppConfiguration
public class SpringDb14ApplicationTests {
...
}