Spring Property Injection Concepts: Difference between revisions

From NovaOrdis Knowledge Base
Jump to navigation Jump to search
 
(176 intermediate revisions by the same user not shown)
Line 2: Line 2:


* [[Spring_Framework#Spring_Framework_Core_Technologies_Concepts|Spring Framework]]
* [[Spring_Framework#Spring_Framework_Core_Technologies_Concepts|Spring Framework]]
* [[Spring Boot Property Injection]]


=Overview=
=Overview=


Spring has two different, but related kinds of configurations: '''bean wiring''', which refers to declaring application components and their dependencies, and how those dependencies should be injected into each other, as described in the [[Spring_Dependency_Injection_and_Inversion_of_Control_Container_Concepts|Dependency Injection and Inversion of Control Container]] section, and '''property injection''', which is the process that allows external pieces of data, known as [[#Configuration_Property|configuration properties]], to be provided to the application runtime at startup or while it is running, in form of Java system properties, environment variables and by other means. This section addresses property injection concepts.
Spring has two different, but related kinds of configuration: '''bean wiring''', which refers to declaring application components and their dependencies, and how those dependencies should be injected into each other, as described in the [[Spring_Dependency_Injection_and_Inversion_of_Control_Container_Concepts|Dependency Injection and Inversion of Control Container]] section, and '''property injection''', which is the process that allows external pieces of data, known as [[#Configuration_Property|configuration properties]], to be provided to the application runtime at startup or while it is running, in form of Java system properties, environment variables and by other means. This section addresses property injection concepts. These two concepts intermingle when we talk about [[#Profiles|profiles]], as both bean wiring and property injection are subject to profiles.
 
=<span id='Spring_Environment'></span><span id='Environment'></span>The Environment Abstraction=
 
The environment is an abstraction integrated in the container that models two key aspects of the application environment: [[#Configuration_Properties|configuration properties]] and [[#Profiles|profiles]].
 
The environment implements [https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/core/env/Environment.html Environment] and can be obtained directly from the application context, as follows:
<syntaxhighlight lang='java'>
import org.springframework.core.env.Environment;
 
ApplicationContext applicationContext = ...
Environment environment = applicationContext.getEnvironment();
</syntaxhighlight>
 
The environment can be injected into a component and accessed programmatically as follows:
 
<syntaxhighlight lang='java'>
@Autowired
private Environment environment;
</syntaxhighlight>


=<span id='Configuration_Property'></span>Configuration Properties=
=<span id='Configuration_Property'></span>Configuration Properties=
Line 11: Line 31:
'''Configuration properties''' are pieces of data coded into Spring components using the [[JavaBeans#Overview|JavaBeans property conventions]]. They usually have a corresponding member variable, a getter and a setter. The Spring Framework provides conventions and mechanisms to automatically inject values into configuration properties, while those values come from several different [[#Property_Sources|property sources]].
'''Configuration properties''' are pieces of data coded into Spring components using the [[JavaBeans#Overview|JavaBeans property conventions]]. They usually have a corresponding member variable, a getter and a setter. The Spring Framework provides conventions and mechanisms to automatically inject values into configuration properties, while those values come from several different [[#Property_Sources|property sources]].


=<span id='Spring_Environment'></span>The Environment Abstraction=
The Spring [[#Environment|environment]] provides the user with a convenient service interface for configuring property sources and resolving properties from them.


The Spring environment is the only source of [[#Configuration_Property|configuration properties]] for components needing them. The environment abstracts the [[#Property_Sources|origins of properties]] and applies [[#Precedence|precedence rules]] when the same property is specified in more than one source. It pulls property values from several sources: [[#Java_System_Properties|Java system properties]], [[#Command-Line_Arguments|command-line arguments]], [[#Environment_Variables|environment variables]], [[#Property_Configuration_Files|configuration files]], etc. The property sources are described in detail in their [[#Property_Sources|corresponding sections]], below.
The Spring [[#Environment|environment]] is the only source of configuration properties for components needing them. The environment abstracts the [[#Property_Sources|origins of properties]] and applies [[#Precedence|precedence rules]] when the same property is specified in more than one source. It pulls property values from several sources: [[#Java_System_Properties|Java system properties]], [[#Command-Line_Arguments|command-line arguments]], [[#Environment_Variables|environment variables]], [[#Property_Configuration_Files|configuration files]], etc. The property sources are described in detail in their [[#Property_Sources|corresponding sections]], below.


<font color=darkgray>TODO: Environment can be injected and inspected.</font>
=Reading Properties from Environment=


=Injecting Properties into Beans=
The availability of a property in one of the environment's property sources can be checked with:


==Configuration Property Holders==
<syntaxhighlight lang='java'>
if (environment.containsProperty(propertyName)) {
  ...
}
</syntaxhighlight>


A common pattern used to handle injected configuration is to declare a '''configuration property holder class''', whose sole purpose in the application is to be holder of configuration data. Such class bundles several configuration properties together, under a common property namespace. There is nothing special about configuration property holders. They are ordinary Spring components that have their properties injected from the [[#Spring_Environment|Spring environment]]. They can be injected inot any other bean that needs those properties. One benefit of this approach is that it keeps configuration-specific details out of controllers and other application specific classes. Another benefit is that it makes it easy to share common configuration properties among several beans that may need this information. All configuration properties related to a certain piece of functionality are kept in a single place, as opposite to being scattered across several components, and if we need to add a new property or change an existing property, we do it in a single place.
If the property is available, it can be obtained with:


<span id='Configuration_Property_Holder_and_Validation'></span>Configuration property holder classes are a good location to apply [[Spring_Validation_Concepts#JavaBean_Validation_and_Configuration_Property_Holders|JavaBeans Validation]] annotations.
<syntaxhighlight lang='java'>
environment.getProperty(propertyName);
</syntaxhighlight>
 
Spring Boot offers a facility to inject property values into components coded using JavaBeans conventions:
 
{{Internal|Spring Boot Property Injection|Spring Boot Property Injection}}


=The PropertySource Abstraction=
The [[#Environment|Spring environment abstraction]] integrates and searches over a configurable hierarchy of [[#Property_Sources|property sources]], consolidated under a [https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/core/env/PropertySources.html PropertySources] interface, each implementing [https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/core/env/PropertySource.html PropertySource]. The mechanism is configurable, custom property sources can be integrated.
==Property Sources==
===Java System Properties===
Java system properties are exposed to the environment via a [https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/core/env/PropertySource.html PropertySource] wrapped around <tt>System.getProperties()</tt>. Properties declared with -D on java command line are available via the environment abstraction.
====Java System Properties Name Translation Syntax and Rules====
A "secretApiKey" variable in the "novaordis.playground" name space can be set as:
-Dnovaordis.playground.secretApiKey=...
===Environment Variables===
Environment variables are exposed to the environment via a [https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/core/env/PropertySource.html PropertySource] wrapped around <tt>System.getenv()</tt>.
The naming style should accommodate restrictions placed on environment variable names by the operating system.
export SERVER_PORT=9999
The environment variables present in the Spring application environment are automatically converted to system property, using specific [[#Name_Translation_Rules|name translation rules]], and they're available in the [[#Enviornment|environment]].
====<span id='Name_Translation_Rules'></span>Environment Variable Name Translation Syntax and Rules====
MY_TEST_ENVIRONMENT_VARIABLE -> my.test.environment.variable
A "secretApiKey" variable in the "novaordis.playground" name space can be set as:
NOVAORDIS_PLAYGROUND_SECRET_API_KEY.
===<span id='Command-Line_Arguments'></span>Spring Boot Command-Line Arguments===
This option to specify system property is only available to [[Spring Boot]] applications.
<font color=darkgray>Do test.</font>
java -jar ... --<''property.name''>=<''value''>
Example:
java -jar ... --server.port=9999
===Property Configuration Files===
====application.properties====
{{Internal|application.properties|application.properties}}
====application.yml====
{{Internal|application.yml|application.yml}}
====bootstrap.yml====
{{Internal|bootstrap.yml|bootstrap.yml}}
===Map Objects===
===JNDI===
===Servlet Configuration===
Servlet configuration is accessible through a <tt>StandardServletEnvironment</tt>.
===Servlet Context Parameters===
Servlet context parameters are accessible through a <tt>StandardServletEnvironment</tt>.
===<span id='Configuration_Service'></span>Configuration Service (Spring Cloud Config Server)===
The configuration service is also referred to as config (configuration) server. For more details, see:
{{Internal|Spring Cloud Config Server|Spring Cloud Config Server}}
===Custom Property Source===
====API====
<syntaxhighlight lang='java'>
ConfigurableApplicationContext ctx = ...
MutablePropertySources sources = ctx.getEnvironment().getPropertySources();
sources.addFirst(new MyPropertySource());
</syntaxhighlight>
====@PropertySource====
{{Internal|@PropertySource|@PropertySource}}
<font color=darkgray>TODO [https://docs.spring.io/spring-framework/docs/current/spring-framework-reference/core.html#beans-using-propertysource Spring Framework Core Technologies Section 1.13.3 Using @PropertySource]</font>
==Precedence==
Property values are not merged but rather completely overridden by a preceding entry. The property sources are scanned in the descending order of their priority, and when a hit is encountered, the scan ends, and the found value is returned. For a StandardEnvironment, the full hierarchy is as follows, with the highest-precedence entries at the top:
# JVM [[#Java_System_Properties|system properties]] (-D command-line arguments).
# OS [[#Environment_Variables|environment variables]].
# <font color=darkgray>application.properties</font>
For a StandardServletEnvironment, the full hierarchy is as follows, with the highest-precedence entries at the top:
# [[#Servlet_Configuration|ServletConfig parameters]].
# [[#Servlet_Context_Parameters|ServletContext parameters]] (web.xml context-param entries).
# JNDI environment variables (java:comp/env/ entries).
# JVM [[#Java_System_Properties|system properties]] (-D command-line arguments).
# OS [[#Environment_Variables|environment variables]].
=Property Placeholders=
Property placeholders can be used in XML configuration elements (but not in other property values - that [[Spring_Boot_Property_Injection#Configuration_Property_Placeholders|only works in Spring Boot]]). Historically, the value of placeholders in elements could be resolved only against JVM system properties or environment variables, but with the recent versions of the Spring Framework, that is no longer the case, because the [[#Environment|environment abstraction]] is integrated throughout the container. More details here: [https://docs.spring.io/spring-framework/docs/current/spring-framework-reference/core.html#beans-placeholder-resolution-in-statements Spring Framework Core Technologies Section 1.13.4 Placeholder Resolution in Statements].
Also see: {{Internal|Spring_Boot_Property_Injection#Configuration_Property_Placeholders|Spring Boot Property Injection - Configuration Property Placeholders}}
=<span id='Profile'></span>Profiles=
{{External|https://www.baeldung.com/spring-profiles}}
A '''profile''' is a named, logical group of bean definitions and [[#Configuration_Properties|configuration properties]] to be registered with the container only if the given profile is [[#Active_Profile|active]]. Beans may be assigned to a profile whether they are defined in XML or with [[#@Profile|annotations]]. The [[#Environment|environment]] determines which profiles - if any - are currently [[#Active_Profile|active]], and which profiles - if any - should be active by [[#Default_Profile|default]]. Profiles are a solution for the problem posed by the fact that configuration details differ when applications are deployed in different runtime environments. The classical example is the database URL and credentials: the testing environment uses a different database than the production environment. One way to address the problem is to configure these details with environment variables. Another option is to use profiles.
==Default Profile==
A '''default profile''' represents the profile (or profiles) that are enabled by default. The default profile's name is "default". Components can be declared to be registered by default, <font color=darkgray>probably redundantly</font> with:
<syntaxhighlight lang='java'>
<syntaxhighlight lang='java'>
@Component
@Profile("default")
@ConfigurationProperties(prefix = "playground.spring.pi.example01")
...
@Data
</syntaxhighlight>
@Validated
If no profile is active, all components belonging to the default profile are created and registered. The default profile is a way to provide a default definition for one or more beans. If any profile is enabled, the default profile does not apply. The name of the default profile can be changed by using <tt>setDefaultProfiles()</tt> on the [[#Environment|Environment]] or declaratively by using the "spring.profiles.default" property.
public class MyPropertyConfiguration {
 
{{Note|Relationship between default and active profiles.}}
 
==Active Profile==
 
More than one profile can be active at a time.
 
A profile, or more than one profiles can be activated declaratively using the <tt>spring.profiles.active</tt> system property. When more than one profile is active, the names of the active profiles should be separated by comma:


  public static final int DEFAULT_SIZE = 20;
<syntaxhighlight lang='bash'>
  public static final String DEFAULT_COLOR = "blue";
java -Dspring.profiles.active="red[,blue,...]" ...
</syntaxhighlight>


  @Min(value = 5, message = "the size must be larger or equal than 5")
the SPRING_PROFILES_ACTIVE environment variable (note that SPRING_ACTIVE_PROFILES has no effect). This is the preferred method to communicate to a containerized Spring Boot application which profile(s) is active:
  @Max(value = 40, message = "the size must be smaller or equal than 40")
  private int size = DEFAULT_SIZE;
  private String color = DEFAULT_COLOR;


}
<syntaxhighlight lang='bash'>
export SPRING_PROFILES_ACTIVE="red[,blue,...]"
</syntaxhighlight>
</syntaxhighlight>


Conventionally, hardcoded defaults are specified as initialization values for the member variables.
servlet context parameters in web.xml, JNDI entries, etc.


The full playground project is available here: {{External|[https://github.com/ovidiuf/playground/tree/master/spring/property-injection/01-environment-and-property-sources Playground Property Injection Example]}}
Spring Boot allows for a [[Spring_Boot_Property_Injection#Active_Profile|special command-line syntax to specify the active profile]].


==Exposing Individual Configuration Properties on Components==
Active profiles can be determined programmatically from the [https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/core/env/Environment.html Environment] interface at runtime:


Individual properties can also be injected directly into established components, as shown below. However, if you have the option, bundling configuration properties into [[#Configuration_Property_Holders|configuration property holders]] is generally a better approach, for the reasons presented above.
<syntaxhighlight lang='java'>
@Autowire
Environment environment;
...
environment.getActiveProfiles()
</syntaxhighlight>
 
Active profiles can also be activated programmatically via the API exposed by the [https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/core/env/Environment.html Environment] interface:
 
{{Warn|For the programmatic configuration to work, <tt>setActiveProfile()</tt> needs to be called before the components are registered with <tt>register()</tt>, as shown in the example below.}}


<syntaxhighlight lang='java'>
<syntaxhighlight lang='java'>
TODO
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
applicationContext.getEnvironment().setActiveProfiles("blue");
applicationContext.scan("playground.spring.profile");
applicationContext.refresh();
</syntaxhighlight>
</syntaxhighlight>


==Configuration Property Metadata==
===Active Profile Example===


==Property Injection and Auto-Configuration==
{{External|[https://github.com/ovidiuf/playground/tree/master/spring/property-injection/02-bean-definition-profiles Playground Active Profile Example]}}


The beans that are automatically configured by the Spring Boot autoconfiguration. process are all configurable by properties drawn from the [[#Spring_Environment|Spring environment]].
===Active Profiles in Integration Tests===


=Property Sources=
In integration tests, the association between a test and active profile (profiles) can be declared with the [[@ActiveProfiles]] annotation:


==Java System Properties==
{{Internal|Spring_Framework_Testing_Concepts#Activating_Profiles_for_Integration_Tests|Activating Profiles for Integration Tests}}


==Command-Line Arguments==
==<span id='Profile_Expression'></span>Profile Expressions==


java -jar ... --<''property.name''>=<''value''>
The profile string may contain a simple profile name or a '''profile expression'''. A profile expression allows for more complicated profile logic to be expressed, and supports the following operators:
Example:
* "!": logical "not"
  java -jar ... --server.port=9999
* "&": logical "and"
* "|":  logical "or"
 
"&" and "|" cannot be mixed without using parentheses.
 
==Bean Definition Profiles==


==Environment Variables==
Bean definition profiles provide a mechanism in the core of the container that allows for registration of different beans in different environments, or according to different conditions. Beans can be associated with [[#Profiles|profiles]] and they are only registered if the associated profile or profiles are active. Note that if more than one valid candidates are found associated with the same active profile, the runtime fails with:


The naming style should accommodate restrictions placed on environment variable names by the operating system.
<syntaxhighlight lang='text'>
org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'playground.spring.profile.ColorAware' available: expected single matching bean but found 2: componentA,componentB
</syntaxhighlight>


export SERVER_PORT=9999
===@Profile===


==Property Configuration Files==
The [[@Profile]] annotation is used to associate the component with one or more active profiles: the component annotated as such becomes eligible for registration, and will be instantiated and registered only if at least one of the profiles is associated with it is active.


===application.properties===
<syntaxhighlight lang='java'>
import org.springframework.context.annotation.Profile;
import org.springframework.stereotype.Component;
...
@Component
@Profile("red")
public class ComponentA implements ColorAware {
  ...
}
...
@Component
@Profile("blue")
public class ComponentB implements ColorAware {
  ...
}
</syntaxhighlight>


{{Internal|application.properties|application.properties}}
More than one profile can be specified:
<syntaxhighlight lang='java'>
@Component
@Profile({"yellow", "green"})
public class ComponentC implements ColorAware {
  ...
}
</syntaxhighlight>


==Configuration Service==
If a [[@Configuration]] class is marked with [[@Profile]], all of the [[@Bean]] methods and [[@Import]] annotations are bypassed unless one or more of the specified profiles are active.


The configuration service is also referred to as configuration server.
[[@Profile]] can be declared at method level in a [[@Configuration]] class. With [[@Profile]] on [[@Bean]] methods, a special scenario may apply: in the case of overloaded methods of the same Java method name (analogous to constructor overloading), a [[@Profile]] condition needs to be consistently declared on all overloaded methods. If the conditions are inconsistent, only the condition on the first declaration among the overloaded methods matters. Therefore, [[@Profile]] can not be used to select an overloaded method with a particular argument signature over another. Resolution between all factory methods for the same bean follows Spring’s constructor resolution algorithm at creation time. If you want to define alternative beans with different profile conditions, use distinct Java method names that point to the same bean name by using the [[@Bean]] name attribute. If the argument signatures are all the same (for example, all of the variants have no-arg factory methods), this is the only way to represent such an arrangement in a valid Java class in the first place, since there can only be one method of a particular name and argument signature.


==Precedence==
@Profile can be used as meta-annotation, for the purpose of creating composed annotations: a custom annotation can be annotated with @Profie, and the custom annotation inherits the semantics provided by the @Profile annotation.


=Profiles=
The association with one or more profile can be more complex when it is declared with a [[#Profile_Expression|profile expression]].


=TODO=
==Spring Boot and Profiles==


<font color=darkgray>
{{Internal|Spring_Boot_Property_Injection#Spring_Boot_and_Profiles|Spring Boot and Profiles}}
* Diagram with property sources and their relative priority, including the configuration service (chapter 14).
* Augment https://kb.novaordis.com/index.php/Spring_Boot_Concepts#Autoconfiguration with specialized sections on property injection for DataSources, etc.
* How do I read the effective values of all configuration properties during testing and at runtime?
* You can figure out the active profile from within a Spring application by @Autowire-ing org.springframework.core.env.Environment and inspecting it.
* https://docs.spring.io/spring-boot/docs/2.1.0.RELEASE/reference/htmlsingle/#configuration-metadata-annotation-processor
</font>

Latest revision as of 03:28, 18 April 2019

Internal

Overview

Spring has two different, but related kinds of configuration: bean wiring, which refers to declaring application components and their dependencies, and how those dependencies should be injected into each other, as described in the Dependency Injection and Inversion of Control Container section, and property injection, which is the process that allows external pieces of data, known as configuration properties, to be provided to the application runtime at startup or while it is running, in form of Java system properties, environment variables and by other means. This section addresses property injection concepts. These two concepts intermingle when we talk about profiles, as both bean wiring and property injection are subject to profiles.

The Environment Abstraction

The environment is an abstraction integrated in the container that models two key aspects of the application environment: configuration properties and profiles.

The environment implements Environment and can be obtained directly from the application context, as follows:

import org.springframework.core.env.Environment;

ApplicationContext applicationContext = ...
Environment environment = applicationContext.getEnvironment();

The environment can be injected into a component and accessed programmatically as follows:

@Autowired
private Environment environment;

Configuration Properties

Configuration properties are pieces of data coded into Spring components using the JavaBeans property conventions. They usually have a corresponding member variable, a getter and a setter. The Spring Framework provides conventions and mechanisms to automatically inject values into configuration properties, while those values come from several different property sources.

The Spring environment provides the user with a convenient service interface for configuring property sources and resolving properties from them.

The Spring environment is the only source of configuration properties for components needing them. The environment abstracts the origins of properties and applies precedence rules when the same property is specified in more than one source. It pulls property values from several sources: Java system properties, command-line arguments, environment variables, configuration files, etc. The property sources are described in detail in their corresponding sections, below.

Reading Properties from Environment

The availability of a property in one of the environment's property sources can be checked with:

if (environment.containsProperty(propertyName)) {
  ...
}

If the property is available, it can be obtained with:

environment.getProperty(propertyName);

Spring Boot offers a facility to inject property values into components coded using JavaBeans conventions:

Spring Boot Property Injection

The PropertySource Abstraction

The Spring environment abstraction integrates and searches over a configurable hierarchy of property sources, consolidated under a PropertySources interface, each implementing PropertySource. The mechanism is configurable, custom property sources can be integrated.

Property Sources

Java System Properties

Java system properties are exposed to the environment via a PropertySource wrapped around System.getProperties(). Properties declared with -D on java command line are available via the environment abstraction.

Java System Properties Name Translation Syntax and Rules

A "secretApiKey" variable in the "novaordis.playground" name space can be set as:

-Dnovaordis.playground.secretApiKey=...

Environment Variables

Environment variables are exposed to the environment via a PropertySource wrapped around System.getenv().

The naming style should accommodate restrictions placed on environment variable names by the operating system.

export SERVER_PORT=9999

The environment variables present in the Spring application environment are automatically converted to system property, using specific name translation rules, and they're available in the environment.

Environment Variable Name Translation Syntax and Rules

MY_TEST_ENVIRONMENT_VARIABLE -> my.test.environment.variable

A "secretApiKey" variable in the "novaordis.playground" name space can be set as:

NOVAORDIS_PLAYGROUND_SECRET_API_KEY.

Spring Boot Command-Line Arguments

This option to specify system property is only available to Spring Boot applications.

Do test.

java -jar ... --<property.name>=<value>

Example:

java -jar ... --server.port=9999

Property Configuration Files

application.properties

application.properties

application.yml

application.yml

bootstrap.yml

bootstrap.yml

Map Objects

JNDI

Servlet Configuration

Servlet configuration is accessible through a StandardServletEnvironment.

Servlet Context Parameters

Servlet context parameters are accessible through a StandardServletEnvironment.

Configuration Service (Spring Cloud Config Server)

The configuration service is also referred to as config (configuration) server. For more details, see:

Spring Cloud Config Server

Custom Property Source

API

ConfigurableApplicationContext ctx = ...
MutablePropertySources sources = ctx.getEnvironment().getPropertySources();
sources.addFirst(new MyPropertySource());

@PropertySource

@PropertySource

TODO Spring Framework Core Technologies Section 1.13.3 Using @PropertySource

Precedence

Property values are not merged but rather completely overridden by a preceding entry. The property sources are scanned in the descending order of their priority, and when a hit is encountered, the scan ends, and the found value is returned. For a StandardEnvironment, the full hierarchy is as follows, with the highest-precedence entries at the top:

  1. JVM system properties (-D command-line arguments).
  2. OS environment variables.
  3. application.properties

For a StandardServletEnvironment, the full hierarchy is as follows, with the highest-precedence entries at the top:

  1. ServletConfig parameters.
  2. ServletContext parameters (web.xml context-param entries).
  3. JNDI environment variables (java:comp/env/ entries).
  4. JVM system properties (-D command-line arguments).
  5. OS environment variables.

Property Placeholders

Property placeholders can be used in XML configuration elements (but not in other property values - that only works in Spring Boot). Historically, the value of placeholders in elements could be resolved only against JVM system properties or environment variables, but with the recent versions of the Spring Framework, that is no longer the case, because the environment abstraction is integrated throughout the container. More details here: Spring Framework Core Technologies Section 1.13.4 Placeholder Resolution in Statements.

Also see:

Spring Boot Property Injection - Configuration Property Placeholders

Profiles

https://www.baeldung.com/spring-profiles

A profile is a named, logical group of bean definitions and configuration properties to be registered with the container only if the given profile is active. Beans may be assigned to a profile whether they are defined in XML or with annotations. The environment determines which profiles - if any - are currently active, and which profiles - if any - should be active by default. Profiles are a solution for the problem posed by the fact that configuration details differ when applications are deployed in different runtime environments. The classical example is the database URL and credentials: the testing environment uses a different database than the production environment. One way to address the problem is to configure these details with environment variables. Another option is to use profiles.

Default Profile

A default profile represents the profile (or profiles) that are enabled by default. The default profile's name is "default". Components can be declared to be registered by default, probably redundantly with:

@Profile("default")
...

If no profile is active, all components belonging to the default profile are created and registered. The default profile is a way to provide a default definition for one or more beans. If any profile is enabled, the default profile does not apply. The name of the default profile can be changed by using setDefaultProfiles() on the Environment or declaratively by using the "spring.profiles.default" property.


Relationship between default and active profiles.

Active Profile

More than one profile can be active at a time.

A profile, or more than one profiles can be activated declaratively using the spring.profiles.active system property. When more than one profile is active, the names of the active profiles should be separated by comma:

java -Dspring.profiles.active="red[,blue,...]" ...

the SPRING_PROFILES_ACTIVE environment variable (note that SPRING_ACTIVE_PROFILES has no effect). This is the preferred method to communicate to a containerized Spring Boot application which profile(s) is active:

export SPRING_PROFILES_ACTIVE="red[,blue,...]"

servlet context parameters in web.xml, JNDI entries, etc.

Spring Boot allows for a special command-line syntax to specify the active profile.

Active profiles can be determined programmatically from the Environment interface at runtime:

@Autowire
Environment environment;
...
environment.getActiveProfiles()

Active profiles can also be activated programmatically via the API exposed by the Environment interface:


For the programmatic configuration to work, setActiveProfile() needs to be called before the components are registered with register(), as shown in the example below.

AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
applicationContext.getEnvironment().setActiveProfiles("blue");
applicationContext.scan("playground.spring.profile");
applicationContext.refresh();

Active Profile Example

Playground Active Profile Example

Active Profiles in Integration Tests

In integration tests, the association between a test and active profile (profiles) can be declared with the @ActiveProfiles annotation:

Activating Profiles for Integration Tests

Profile Expressions

The profile string may contain a simple profile name or a profile expression. A profile expression allows for more complicated profile logic to be expressed, and supports the following operators:

  • "!": logical "not"
  • "&": logical "and"
  • "|": logical "or"

"&" and "|" cannot be mixed without using parentheses.

Bean Definition Profiles

Bean definition profiles provide a mechanism in the core of the container that allows for registration of different beans in different environments, or according to different conditions. Beans can be associated with profiles and they are only registered if the associated profile or profiles are active. Note that if more than one valid candidates are found associated with the same active profile, the runtime fails with:

org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'playground.spring.profile.ColorAware' available: expected single matching bean but found 2: componentA,componentB

@Profile

The @Profile annotation is used to associate the component with one or more active profiles: the component annotated as such becomes eligible for registration, and will be instantiated and registered only if at least one of the profiles is associated with it is active.

import org.springframework.context.annotation.Profile;
import org.springframework.stereotype.Component;
...
@Component
@Profile("red")
public class ComponentA implements ColorAware {
  ...
}
...
@Component
@Profile("blue")
public class ComponentB implements ColorAware {
  ...
}

More than one profile can be specified:

@Component
@Profile({"yellow", "green"})
public class ComponentC implements ColorAware {
  ...
}

If a @Configuration class is marked with @Profile, all of the @Bean methods and @Import annotations are bypassed unless one or more of the specified profiles are active.

@Profile can be declared at method level in a @Configuration class. With @Profile on @Bean methods, a special scenario may apply: in the case of overloaded methods of the same Java method name (analogous to constructor overloading), a @Profile condition needs to be consistently declared on all overloaded methods. If the conditions are inconsistent, only the condition on the first declaration among the overloaded methods matters. Therefore, @Profile can not be used to select an overloaded method with a particular argument signature over another. Resolution between all factory methods for the same bean follows Spring’s constructor resolution algorithm at creation time. If you want to define alternative beans with different profile conditions, use distinct Java method names that point to the same bean name by using the @Bean name attribute. If the argument signatures are all the same (for example, all of the variants have no-arg factory methods), this is the only way to represent such an arrangement in a valid Java class in the first place, since there can only be one method of a particular name and argument signature.

@Profile can be used as meta-annotation, for the purpose of creating composed annotations: a custom annotation can be annotated with @Profie, and the custom annotation inherits the semantics provided by the @Profile annotation.

The association with one or more profile can be more complex when it is declared with a profile expression.

Spring Boot and Profiles

Spring Boot and Profiles