What External Properties and Profiles Mean in Spring
External properties are configuration values that live outside your compiled code — in application.properties, environment variables, command-line arguments, JNDI, or a file on the production server. Spring reads them all through one abstraction, the Environment, so your code never needs to know where a value came from.
Profiles are named groups that decide which beans get created and which property files get loaded. A profile called dev might wire an in-memory database, while prod wires a connection pool against a real one — same code, different configuration.
On the 2V0-72.22 exam, this is objective 1.3 "Properties and Profiles" inside the Spring Core section (28% of questions), and it appears again in the Spring Boot section (28%) as "describe options for defining and loading properties". Expect questions on which property source wins when two sources define the same key, the difference between @Value and @ConfigurationProperties, how @Profile expressions evaluate, and what a profile-specific file actually does.
Version note: The exam targets Spring Framework 5.3 / Spring Boot 2.5–2.7. Everything below applies to Spring Boot 3.x as well, and every place where behaviour changed at Boot 2.4 or Boot 3.0 is called out explicitly — Boot 2.4 rewrote config file processing, and a lot of study material still describes the old rules.
The Short Answer
If you only memorise five things from this guide, memorise these:
- Later sources override earlier ones, and command-line arguments beat everything in a normal application run.
--server.port=9090wins over a system property, an environment variable, andapplication.properties. - Java system properties beat OS environment variables. Most candidates get this backwards.
@PropertySourcesits belowapplication.properties, so it can never override it.- Profile-specific files are layered on top of the plain file, not swapped for it.
application-dev.propertiesoverridesapplication.propertieskey by key; keys it does not mention still come from the plain file. @Valueinjects one value and supports SpEL;@ConfigurationPropertiesbinds a whole group and supports relaxed binding and validation. Neither does the other's job.
Where Properties Come From: The Precedence Order
Spring Boot collects property sources into an ordered list. When you ask for server.port, the first source that has it wins. The official reference lists these lowest-priority first; the ladder below is inverted, because the question you actually ask is "what wins?"
- 1Devtools global settingsdev only~/.config/spring-boot — development machines only
- 2Test annotationstests only@TestPropertySource, @DynamicPropertySource, @SpringBootTest(properties)
- 3Command-line arguments--server.port=9090
- 4SPRING_APPLICATION_JSONInline JSON in an environment variable or system property
- 5Servlet init parametersServletConfig first, then ServletContext
- 6JNDI attributesjava:comp/env
- 7Java system properties-Dserver.port=9090
- 8OS environment variablesSERVER_PORT=9090
- 9random.* valuesRandomValuePropertySource
- 10Config data filesgroupapplication.properties / .yml — see the nested order below
- 11@PropertySourceOn a @Configuration class — below application.properties, not above it
- 12Default propertiesSpringApplication.setDefaultProperties(…)
- 1.Profile-specific, outside the jar — application-{profile}.properties
- 2.Plain, outside the jar — application.properties
- 3.Profile-specific, inside the jar
- 4.Plain, inside the jar
External beats packaged, and profile-specific beats plain — but a packaged profile-specific file still loses to a plain file outside the jar.
The same order as a table, with the example you are most likely to see in a question:
| # | Property source | Example |
|---|---|---|
| 1 | Devtools global settings | ~/.config/spring-boot (development machines only) |
| 2 | Test annotations | @TestPropertySource, @DynamicPropertySource, @SpringBootTest(properties = …) |
| 3 | Command-line arguments | java -jar app.jar --server.port=9090 |
| 4 | SPRING_APPLICATION_JSON | SPRING_APPLICATION_JSON='{"server":{"port":9090}}' |
| 5 | Servlet init parameters | ServletConfig first, then ServletContext |
| 6 | JNDI attributes | java:comp/env |
| 7 | Java system properties | java -Dserver.port=9090 -jar app.jar |
| 8 | OS environment variables | SERVER_PORT=9090 |
| 9 | RandomValuePropertySource | app.id=${random.uuid} |
| 10 | Config data files | application.properties / application.yml |
| 11 | @PropertySource | @PropertySource("classpath:extra.properties") |
| 12 | Default properties | SpringApplication.setDefaultProperties(…) |
Exam tip: System properties (
-D) beat environment variables, not the other way round. Both beat anything inapplication.properties. This single ordering fact accounts for a large share of the property questions candidates get wrong.
Exam tip:
@PropertySourceis at position 11 — below config data files. A key defined in bothapplication.propertiesand a@PropertySourcefile resolves to theapplication.propertiesvalue. If a question offers "the@PropertySourcevalue overridesapplication.properties", it is wrong.
The Four Config Data Locations
Rung 10 is itself an ordered group. Within config data files, later wins:
| Priority | Location |
|---|---|
| Highest | Profile-specific file outside the jar — ./config/application-prod.properties |
| ↓ | Plain file outside the jar — ./application.properties |
| ↓ | Profile-specific file inside the jar |
| Lowest | Plain file inside the jar |
Exam tip: External beats packaged, and profile-specific beats plain — but the grouping matters: a packaged profile-specific file still loses to a plain file outside the jar. Externalising a file promotes it above everything bundled in the artifact.
Spring Boot searches a fixed list of default locations for config data, and later locations override earlier ones:
classpath:/
classpath:/config/
file:./
file:./config/
file:./config/*/The last entry means the immediate subdirectories of config/, which is how mounted configuration volumes are picked up without naming each one.
You can change what it looks for with spring.config.name (default application), or where it looks with spring.config.location (replaces the defaults) and spring.config.additional-location (adds to them).
java -jar app.jar --spring.config.name=myapp
java -jar app.jar --spring.config.location=file:/etc/myapp/
java -jar app.jar --spring.config.additional-location=file:/etc/myapp/Exam tip:
spring.config.locationreplaces the default search locations;spring.config.additional-locationadds to them. Swapping the two is a common distractor.
application.properties vs application.yml
Spring Boot accepts both formats, and they are equivalent in capability. The .properties format is flat key/value; YAML is hierarchical and better for deeply nested configuration.
spring.datasource.url=jdbc:postgresql://localhost/orders
spring.datasource.username=app
app.retry.max-attempts=3
app.allowed-origins=https://a.example,https://b.examplespring:
datasource:
url: "jdbc:postgresql://localhost/orders"
username: "app"
app:
retry:
max-attempts: 3
allowed-origins:
- "https://a.example"
- "https://b.example"Exam tip: If
application.propertiesandapplication.ymlexist in the same location,.propertiestakes precedence. The recommendation is to pick one format per application and stay with it.
Both formats support multi-document files, where each document can be activated conditionally. YAML separates documents with ---; the properties format uses a comment-style separator #---.
app.mode: "shared"
---
spring:
config:
activate:
on-profile: "prod"
app.mode: "strict"app.mode=shared
#---
spring.config.activate.on-profile=prod
app.mode=strictExam tip: YAML files cannot be loaded through
@PropertySourceor@TestPropertySource. Those annotations understand the.propertiesformat only. If you need YAML in a test, use@ActiveProfileswith a profile-specific YAML file, or register the source yourself.
YAML also binds lists positionally, which matters when an environment variable has to override one:
app:
servers:
- "one.example"
- "two.example"The equivalent flat keys are app.servers[0] and app.servers[1].
Reading Properties: @Value, Environment and SpEL
Property Placeholders with @Value
@Value injects a single resolved value into a field, constructor parameter, or method parameter.
@Service
public class ReportService {
private final int timeoutMs;
public ReportService(@Value("${app.timeout-ms:5000}") int timeoutMs) {
this.timeoutMs = timeoutMs;
}
}The :5000 after the key is a default value, used when the property is absent.
Exam tip: Without a default, an unresolvable placeholder fails the context at startup, not at first use.
@Value("${app.missing}")throwsIllegalArgumentException: Could not resolve placeholder 'app.missing'. That fail-fast behaviour is deliberate and is frequently tested.
${...} Is Not #{...}
This is the single most common syntax trap in the objective:
| Syntax | Name | Resolves to |
|---|---|---|
${...} | Property placeholder | A value from the Environment |
#{...} | SpEL expression | The result of evaluating an expression |
@Value("${app.name}") // property placeholder
private String name;
@Value("#{systemProperties['user.region']}") // SpEL
private String region;
@Value("#{T(java.lang.Math).random() * 100}") // SpEL: static method call
private double sample;
@Value("#{'${app.allowed-origins}'.split(',')}") // both: placeholder inside SpEL
private List<String> origins;Exam tip:
#{...}is evaluated by the Spring Expression Language,${...}by the property placeholder resolver. A placeholder can be nested inside a SpEL expression (as in the last example), because the placeholder is resolved first, but the reverse is not true.
Injecting the Environment Directly
When you need to read a property programmatically, inject Environment:
@Service
public class FeatureService {
private final Environment env;
public FeatureService(Environment env) {
this.env = env;
}
public boolean isEnabled() {
return env.getProperty("app.feature.enabled", Boolean.class, false);
}
public String requiredRegion() {
return env.getRequiredProperty("app.region"); // throws if absent
}
}Environment also answers profile questions: getActiveProfiles(), getDefaultProfiles(), and acceptsProfiles(Profiles.of("dev | test")).
Exam tip: In a plain Spring application (no Boot),
${...}placeholders in@Valueonly work if astatic PropertySourcesPlaceholderConfigurerbean is registered. Spring Boot registers it for you, which is why the annotation "just works" there. The bean must bestaticso it is instantiated early, before other beans are configured.
@PropertySource: Loading Extra Files
@PropertySource adds a .properties file to the Environment from a @Configuration class. It is core Spring, not Boot, and it is what the exam expects you to reach for when a question is not Boot-specific.
@Configuration
@PropertySource("classpath:integration.properties")
@PropertySource(value = "file:/etc/app/override.properties", ignoreResourceNotFound = true)
public class IntegrationConfig {
}Key behaviours:
| Behaviour | Detail |
|---|---|
| Formats | .properties and XML properties files — not YAML |
| Missing file | Fails the context unless ignoreResourceNotFound = true |
Duplicate keys across several @PropertySource | The last annotation processed wins |
Precedence vs application.properties | Lower — cannot override config data |
| Repeatable | Yes; @PropertySources is the container annotation |
Resource prefixes work as everywhere else in Spring: classpath:, file:, and http:.
@ConfigurationProperties: Type-Safe Binding
@Value is fine for one or two values. Once a component needs a group of related settings, @ConfigurationProperties binds them to a typed object in one step.
@ConfigurationProperties(prefix = "app.retry")
public class RetryProperties {
private int maxAttempts = 3;
private Duration backoff = Duration.ofSeconds(1);
public int getMaxAttempts() { return maxAttempts; }
public void setMaxAttempts(int maxAttempts) { this.maxAttempts = maxAttempts; }
public Duration getBackoff() { return backoff; }
public void setBackoff(Duration backoff) { this.backoff = backoff; }
}app.retry.max-attempts=5
app.retry.backoff=2sNote that Duration binds from 2s, 500ms or PT2S without any custom conversion — Spring Boot ships converters for Duration, Period, DataSize and enums.
Three Ways to Register It
| Registration | How | When to use |
|---|---|---|
@EnableConfigurationProperties(RetryProperties.class) | On a @Configuration class | Explicit, and the only option for constructor-bound types you do not scan |
@ConfigurationPropertiesScan | On the application class | Scans a package for @ConfigurationProperties types |
@Component on the properties class | Stereotype + component scanning | Simple setter-bound classes only |
Exam tip: A
@ConfigurationPropertiesclass is not picked up automatically just because it carries the annotation. It must be registered through one of the three routes above. A question showing only the annotated class and asking "why is nothing bound?" is testing exactly this.
Relaxed Binding
@ConfigurationProperties matches property names loosely, so the same Java field binds from several spellings:
| Form | Example for maxAttempts | Where it works |
|---|---|---|
| Kebab-case | app.retry.max-attempts | Everywhere — the recommended canonical form |
| Camel-case | app.retry.maxAttempts | Properties, YAML, system properties |
| Snake-case | app.retry.max_attempts | Properties, YAML, system properties |
| Upper-case | APP_RETRY_MAXATTEMPTS | Environment variables |
Exam tip: Relaxed binding is a feature of
@ConfigurationPropertiesonly.@Value("${app.retry.max-attempts}")requires the name to match a source exactly — setAPP_RETRY_MAXATTEMPTSas an environment variable and the@ConfigurationPropertiesbinding works while the@Valuemay not. Always write placeholders in the canonical kebab-case form.
Constructor Binding and Immutability
Binding through a constructor produces an immutable configuration object, and a Java record is the shortest way to express it:
@ConfigurationProperties(prefix = "app.retry")
public record RetryProperties(int maxAttempts, @DefaultValue("1s") Duration backoff) {
}Version note: In Boot 2.2–2.6, constructor binding required
@ConstructorBindingon the type. From Boot 3.0, the annotation is allowed on constructors only, and it is needed just to disambiguate when a class has more than one constructor — a single parameterized constructor is used for binding automatically.
Exam tip: A constructor-bound
@ConfigurationPropertiesclass cannot be registered with@Component,@Beanor@Import. Use@EnableConfigurationPropertiesor@ConfigurationPropertiesScan. Defaults for constructor-bound properties come from@DefaultValue, not from field initialisers.
Validation
Add @Validated and standard JSR-303 constraints, and a bad configuration fails the context at startup instead of surfacing as a NullPointerException an hour into production.
@Validated
@ConfigurationProperties(prefix = "app.mail")
public class MailProperties {
@NotBlank
private String host;
@Min(1) @Max(65535)
private int port = 25;
@Valid
private final Retry retry = new Retry();
// getters and setters omitted
}Exam tip: Nested objects are not validated unless the field carries
@Valid.@Validatedon the outer class alone only validates the outer class's own constraints.
You can also apply @ConfigurationProperties to a @Bean method, which is how you bind configuration into a third-party class you cannot annotate:
@Bean
@ConfigurationProperties(prefix = "app.datasource")
public HikariDataSource dataSource() {
return new HikariDataSource();
}That pattern is a useful contrast with @Component vs @Bean: the annotation goes wherever the object is created. Every bound @ConfigurationProperties object is also listed by the Actuator /configprops endpoint — see the Actuator exam guide for how that endpoint and /env sanitize sensitive values.
@Value vs @ConfigurationProperties
- Injects one property at a time
- Supports SpEL: #{...}
- Inline default: ${key:fallback}
- Relaxed binding
- JSR-303 validation
- Lists, maps and nested objects
- Binds a whole group to a typed object
- Relaxed binding: kebab, camel, UPPER_SNAKE
- Lists, maps and nested objects
- JSR-303 validation via @Validated
- Constructor binding gives immutable config
- Supports SpEL
| Feature | @Value | @ConfigurationProperties |
|---|---|---|
| Binds | One value at a time | A whole group, by prefix |
| Relaxed binding | No — exact name | Yes |
SpEL (#{...}) | Yes | No |
| Lists, maps, nested objects | Limited | Yes |
| JSR-303 validation | No | Yes, with @Validated |
| Immutability | final field via constructor | Constructor binding / records |
| Missing property | Startup failure unless a default is given | Left at its default value |
| IDE metadata & completion | No | Yes |
Rule of thumb: reach for @Value when you need one value or an expression, and @ConfigurationProperties when a component owns a coherent block of settings. The Spring team's own auto-configuration classes use @ConfigurationProperties almost exclusively — see how auto-configuration works for how @ConditionalOnProperty then switches beans on and off based on those same values.
Spring Profiles: @Profile and Profile Expressions
@Profile makes a bean definition conditional on the active profiles. It can go on a @Component, on a @Configuration class, or on an individual @Bean method.
@Configuration
@Profile("dev")
public class DevDataSourceConfig {
@Bean
public DataSource dataSource() {
return new EmbeddedDatabaseBuilder().setType(EmbeddedDatabaseType.H2).build();
}
}
@Configuration
@Profile("prod")
public class ProdDataSourceConfig {
@Bean
public DataSource dataSource() {
return new HikariDataSource();
}
}Exam tip:
@Profileon a@Configurationclass disables every@Beanmethod inside it when the profile is not active. Put it on the class when the whole block belongs to one environment, and on individual methods when only some beans do.
Profile Expressions
Since Spring 5.1, @Profile accepts a boolean expression:
| Operator | Meaning | Example |
|---|---|---|
! | NOT | @Profile("!prod") |
& | AND | @Profile("prod & cloud") |
| | OR | @Profile("prod | staging") |
Exam tip: You cannot mix
&and|without parentheses.@Profile("a & b | c")is invalid and throws at startup; write@Profile("(a & b) | c")or@Profile("a & (b | c)").
Listing several profiles in the array form is an OR: @Profile({"dev", "test"}) activates the bean when either is active.
The default Profile
When no profile is explicitly activated, Spring uses a profile named default.
@Bean
@Profile("default")
public DataSource fallbackDataSource() {
return new EmbeddedDatabaseBuilder().build();
}Exam tip: A
@Profile("default")bean is created only while no profile is explicitly active. Start the application with--spring.profiles.active=devand that bean disappears — even thoughdevsays nothing about it.Environment.getActiveProfiles()returns an empty array in that situation, whilegetDefaultProfiles()returns["default"]. Rename the default withspring.profiles.default.
Profile names are validated: letters, digits and the characters -, _, ., + and @ are allowed, and a name must start and end with a letter or digit. Set spring.profiles.validate=false to opt out.
Activating Profiles
spring.profiles.active is an ordinary property, so it obeys the precedence ladder above. That is why a command-line argument beats whatever the packaged application.properties says.
| Mechanism | Example | Notes |
|---|---|---|
application.properties | spring.profiles.active=dev | Lowest of these; a baseline, not a lock |
| Environment variable | SPRING_PROFILES_ACTIVE=prod | Overrides the file |
| System property | -Dspring.profiles.active=prod | Overrides the environment variable |
| Command-line argument | --spring.profiles.active=prod | Overrides the system property |
| Programmatic | application.setAdditionalProfiles("dev") | Adds profiles, does not replace |
| Tests | @ActiveProfiles("test") | Applies to the test context only |
public static void main(String[] args) {
SpringApplication application = new SpringApplication(MyApplication.class);
application.setAdditionalProfiles("dev", "hsqldb");
application.run(args);
}Including and Grouping Profiles
spring.profiles.include adds profiles unconditionally, on top of whatever is active. Included profiles are added before the ones from spring.profiles.active.
spring.profiles.include[0]=common
spring.profiles.include[1]=localspring.profiles.group (Boot 2.4+) defines an alias that expands into several profiles:
spring.profiles.group.production[0]=proddb
spring.profiles.group.production[1]=prodmqRunning with --spring.profiles.active=production now activates production, proddb and prodmq together.
Exam tip:
spring.profiles.active,spring.profiles.default,spring.profiles.includeandspring.profiles.groupcannot appear in a profile-specific document — not inapplication-dev.properties, and not in a document guarded byspring.config.activate.on-profile. Boot fails withInvalidConfigDataPropertyException. Letting a profile activate another profile was possible before Boot 2.4 and is exactly what the rewrite removed.
Profile-Specific Configuration Files
Name a file application-{profile}.properties (or .yml) and Spring Boot loads it in addition to application.properties whenever that profile is active.
# application.properties — shared baseline
app.name=Orders
app.retry.max-attempts=3
logging.level.root=INFO
# application-prod.properties — only the differences
app.retry.max-attempts=10
logging.level.root=WARNWith prod active, app.name is still Orders: the profile-specific file overrides key by key and inherits the rest.
Exam tip: A profile-specific file does not replace the plain file. Candidates who expect
application-prod.propertiesto be the whole configuration get the "what is the value ofapp.name?" question wrong.
When several profiles are active, a last-wins strategy applies. With --spring.profiles.active=prod,live, values in application-live.properties override those in application-prod.properties.
spring.config.activate.on-profile
Instead of separate files, a single multi-document file can hold conditional sections:
app:
mode: "shared"
---
spring:
config:
activate:
on-profile: "prod | staging"
app:
mode: "strict"Version note: This property replaced
spring.profilesin Spring Boot 2.4. Study material that showsspring.profiles: prodinside a YAML document predates the config data rewrite.spring.config.activate.on-profileaccepts the same expression syntax as@Profile, including!,&and|.
A document can also be activated by cloud platform with spring.config.activate.on-cloud-platform=kubernetes.
Importing Extra Config
spring.config.import (Boot 2.4+) pulls in additional configuration, and the imported document is treated as if it sat immediately below the one that declared the import:
spring.config.import=optional:file:./dev.properties
spring.config.import=optional:configtree:/etc/config/The optional: prefix means "do not fail if it is missing". Without it, a missing import fails startup — which is usually what you want for a mounted secret.
Profiles and Properties in Tests
Test annotations sit near the very top of the precedence ladder, which is what makes them able to override anything the application ships with.
@SpringBootTest(properties = "app.retry.max-attempts=1")
@ActiveProfiles("test")
class OrderServiceTest {
// ...
}| Annotation | Purpose |
|---|---|
@ActiveProfiles("test") | Activates profiles for the test context |
@SpringBootTest(properties = …) | Inline property overrides for that test |
@TestPropertySource(properties = …) | Inline overrides, and locations for .properties files |
@DynamicPropertySource | Values known only at runtime, e.g. a Testcontainers port |
Exam tip:
@TestPropertySourceoutranks@SpringBootTest(properties = …), and both outrank command-line arguments and everything below. Like@PropertySource,@TestPropertySourcecannot read YAML.
Each distinct combination of profiles and properties produces a separate cached application context, which is the usual reason a test suite gets slow. The Spring Boot testing exam guide covers context caching and test slices in detail.
Common Exam Traps
1. System properties beat environment variables.
-Dserver.port=9090 wins over SERVER_PORT=8081. Both win over application.properties.
2. @PropertySource cannot override application.properties.
It sits one rung below config data. Distractors that claim otherwise are wrong.
3. @PropertySource and @TestPropertySource cannot load YAML.
Only .properties (and XML properties) files.
4. ${...} and #{...} are different resolvers.
${} is a property placeholder; #{} is SpEL. A placeholder may be nested inside SpEL, never the reverse.
5. @Value has no relaxed binding.
APP_RETRY_MAXATTEMPTS binds into @ConfigurationProperties but may not resolve a @Value placeholder. Write placeholders in canonical kebab-case.
6. A profile-specific file is layered, not swapped.
application-prod.properties overrides individual keys; everything else still comes from application.properties.
7. Profile-activating properties are banned inside profile-specific documents.
spring.profiles.active, .default, .include and .group there cause InvalidConfigDataPropertyException.
8. @Profile("default") beans vanish once any profile is active.
Activating dev removes them, even though dev never mentions them.
9. Mixing & and | without parentheses is invalid.
"a & b | c" throws; write "(a & b) | c".
10. .properties beats .yml in the same location.
Keeping both files around is a real-world footgun and a favourite exam distractor.
11. A @ConfigurationProperties class must be registered.
@EnableConfigurationProperties, @ConfigurationPropertiesScan, or @Component — the annotation alone binds nothing.
12. An unresolvable @Value placeholder fails at startup.
Not at first access. Supply a default with ${key:fallback} if the property is genuinely optional.
Summary
| Concept | Key point |
|---|---|
| Precedence | Later sources win; command-line arguments beat everything in a normal run |
| System vs env | Java system properties (-D) outrank OS environment variables |
| Config data order | External beats packaged; profile-specific beats plain |
.properties vs .yml | .properties wins in the same location |
${} vs #{} | Property placeholder vs SpEL expression |
@Value | One value, SpEL, inline defaults, no relaxed binding |
@ConfigurationProperties | Group binding, relaxed binding, collections, @Validated |
| Registration | @EnableConfigurationProperties / @ConfigurationPropertiesScan / @Component |
@PropertySource | .properties only, below config data, ignoreResourceNotFound |
@Profile | Conditional beans; supports !, &, ` |
default profile | Active only when no profile is explicitly active |
| Activation | spring.profiles.active is a normal property, so the ladder applies |
include / group | Additive activation; both banned in profile-specific documents |
| Profile files | application-{profile} layers over application; last profile wins |
| Boot 2.4 | spring.profiles became spring.config.activate.on-profile |
Properties and profiles look like configuration trivia until you see how many exam questions reduce to one ordering fact. If you can rebuild the precedence ladder from memory and explain what a profile-specific file does to the plain one, you have most of objective 1.3.
Frequently Asked Questions
What is the property precedence order in Spring Boot?
From highest to lowest: devtools global settings, test annotations (@TestPropertySource, @DynamicPropertySource, @SpringBootTest(properties)), command-line arguments, SPRING_APPLICATION_JSON, servlet init parameters, JNDI attributes, Java system properties, OS environment variables, random.* values, config data files (application.properties / .yml), @PropertySource, and finally default properties set through SpringApplication.setDefaultProperties. In a normal application run — no tests, no devtools — command-line arguments win over everything.
Do environment variables override application.properties?
Yes. OS environment variables sit above config data files, so SERVER_PORT=9090 overrides server.port=8080 in application.properties. However, Java system properties override environment variables, and command-line arguments override both. Environment variables use relaxed binding, so APP_RETRY_MAXATTEMPTS binds to app.retry.max-attempts in a @ConfigurationProperties class.
What is the difference between @Value and @ConfigurationProperties?
@Value injects a single property into a field or parameter and supports SpEL expressions with #{...} and inline defaults with ${key:fallback}, but it has no relaxed binding and no validation. @ConfigurationProperties binds a whole group of properties by prefix into a typed object, supports relaxed binding, collections, maps, nested objects, JSR-303 validation via @Validated, and constructor binding for immutability — but it does not support SpEL. Use @Value for one-off values and @ConfigurationProperties when a component owns a block of settings.
How do I activate a Spring profile?
Set the spring.profiles.active property. Because it is an ordinary property, every activation route follows the normal precedence order: application.properties is the weakest, then the SPRING_PROFILES_ACTIVE environment variable, then -Dspring.profiles.active, then --spring.profiles.active=prod on the command line. In code, SpringApplication.setAdditionalProfiles(…) adds profiles rather than replacing them, and in tests @ActiveProfiles applies to that test context only.
Does application-prod.properties replace application.properties?
No. Profile-specific files are loaded in addition to the plain file and override it key by key. Keys that the profile-specific file does not mention keep the values from application.properties. When several profiles are active a last-wins strategy applies, so with spring.profiles.active=prod,live the values in application-live.properties beat those in application-prod.properties.
Can @PropertySource load a YAML file?
No. @PropertySource and @TestPropertySource understand the .properties format (and XML properties files) only — YAML files cannot be loaded through either annotation. Use profile-specific YAML files, spring.config.import, or register a YamlPropertySourceLoader yourself. Remember also that @PropertySource ranks below application.properties, so it cannot override config data.
→ Practice exam-style questions on properties and profiles — free interactive drilling with detailed explanations
→ Spring Boot auto-configuration explained — how @ConditionalOnProperty turns these values into bean decisions
→ Spring Boot testing exam guide — @ActiveProfiles, test property sources, and context caching
→ How to prepare for the Spring Professional exam — complete 8-week study plan
→ Get Full Access — 2600+ Questions — full practice exam bank with detailed explanations