Spring’s Environment combines two concerns: resolving configuration properties
and determining which bean-definition profiles are active. The core framework
defines the abstraction and standard JVM/servlet sources; Spring Boot adds its
own external-configuration sources and precedence rules.
Property Sources and Precedence #
A configurable environment owns ordered PropertySource<?> objects in
MutablePropertySources. Resolution searches from highest to lowest precedence
and returns the first source containing the requested key. Naming and ordering
sources explicitly avoids configuration that changes with registration order:
ConfigurableEnvironment environment = context.getEnvironment();
environment.getPropertySources().addFirst(
new MapPropertySource("deployment", Map.of("orders.timeout", "2s")));StandardEnvironment includes JVM system properties and operating-system
environment variables. StandardServletEnvironment adds servlet configuration,
servlet-context parameters, and optionally JNDI sources. @PropertySource can
add a properties resource while configuration classes are processed.
Source ordering is the policy, not an intrinsic rule that every file, JVM property, or environment variable must win. Spring Boot defines a larger, documented order that includes configuration data and command-line arguments. Tests should add explicit test sources rather than rely on a developer machine’s environment.
Resolution, Defaults, and Types #
The PropertyResolver API supports direct and typed lookup:
Duration timeout =
environment.getProperty("orders.timeout", Duration.class, Duration.ofSeconds(1));Typed access delegates to the configured conversion service. Placeholder syntax
supports ${orders.timeout} and a fallback such as
${orders.timeout:1s}. @Value uses placeholder resolution when the context
has an appropriate embedded value resolver; a
PropertySourcesPlaceholderConfigurer provides that facility in explicit
non-Boot configuration.
Fallbacks are suitable only when the default is operationally valid. Required configuration can be declared and checked before beans consume it:
environment.setRequiredProperties("database.url", "database.user");
environment.validateRequiredProperties();Unresolved required placeholders should fail startup rather than silently select a production-unsafe value. Secrets should enter through a controlled property source and must not be printed while diagnosing resolution.
Profile Expressions #
@Profile makes a component or configuration class conditional on active
profiles. Profile expressions support names, negation with !, conjunction
with &, disjunction with |, and parentheses:
@Configuration
@Profile("production & !maintenance")
class ProductionConfiguration {
}For an array such as @Profile({"blue", "green"}), any element matching
activates the component. Unprofiled definitions remain eligible regardless of
the active set.
When no profile is explicitly active, Spring uses the default profile set,
whose initial value contains default. spring.profiles.default can change
that set. A bean marked @Profile("default") is therefore conditional; it is
not an unconditional fallback when another profile is active.
Activating Profiles #
Profiles can be selected programmatically before refresh:
var context = new AnnotationConfigApplicationContext();
context.getEnvironment().setActiveProfiles("integration");
context.register(TestConfiguration.class);
context.refresh();They can also come from the spring.profiles.active property. JVM
-Dspring.profiles.active=production works with the core standard environment.
Spring Boot additionally accepts command-line configuration and relaxed
environment-variable names such as SPRING_PROFILES_ACTIVE, according to
Boot’s external-configuration rules. Programmatic calls replace or add to the
environment’s active set depending on whether setActiveProfiles or
addActiveProfile is used.
Deterministic Configuration #
Apply the same explicit policy in production and tests:
- Document source names and precedence.
- Activate profiles before context refresh.
- Use
@TestPropertySourceor@DynamicPropertySourcefor test-owned values. - Assert critical resolved values in focused configuration tests.
- Keep profiles coarse-grained; use properties for values rather than creating a profile for every configuration combination.
Comments
Read or comment on GitHub (sign-in required to comment)