configuration-properties/ @ConfigurationProperties vs @Value on Spring Boot 4.1.1. The relaxed-binding matrix is generated by binding each spelling rather than transcribed, and re-checked against real processes -- the in-process probe was wrong twice before it was right. Records the three findings that came out of it: @Value does get relaxed resolution inside Spring Boot (Boot attaches ConfigurationPropertySources), the configuration processor silently stops generating metadata on JDK 23+ when declared as a plain dependency, and @Valid is not what makes nested constraints run. profiles-and-config/ Precedence, profiles, spring.config.import and config trees. /precedence reports every source holding a property in rank order with file and line, which turns "my profile file had no effect" into a two-line answer. Also pins the counterintuitive one: an imported file outranks the file that imported it. spring-aop/ Designators, proxy types, and aspects that do not fire. One advice per supported designator so the reference table is generated from real matches; all fourteen unsupported designators fed to the parser. Two corrections to the reference documentation: unsupported designators throw UnsupportedPointcutPrimitiveException (extends RuntimeException, not IllegalArgumentException), and spring-boot-starter-aop was renamed to spring-boot-starter-aspectj in Boot 4. 19 contract tests across the three modules, 15 captured transcripts, all regenerated by scripts/run-all.sh. Verified on Spring Boot 4.1.1, Spring Framework 7.0.9, JDK 25.0.4.1. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Gip4srpzMwjgoba6uEfbr5
43 lines
1.7 KiB
Markdown
43 lines
1.7 KiB
Markdown
[← Validation](05-validation.md) · [Index](../README.md) · [IDE metadata →](07-ide-metadata.md)
|
|
|
|
# 6. When `@Value` is still the right answer
|
|
|
|
Binding wins most of the time, and this project is largely an argument for it. The exceptions
|
|
are real though, and pretending otherwise makes the advice easy to dismiss.
|
|
|
|
## SpEL
|
|
|
|
`@Value` evaluates SpEL; the binder does not. If the value has to be *computed*, this is the
|
|
only one of the two that can do it:
|
|
|
|
```java
|
|
@Value("#{T(java.lang.Runtime).getRuntime().availableProcessors() * 2}")
|
|
private int computedThreads;
|
|
```
|
|
|
|
There is no `@ConfigurationProperties` equivalent. The binder maps a value; it does not derive
|
|
one. (You can always compute in a compact constructor instead, which is usually clearer.)
|
|
|
|
## A single value in a class that is not about configuration
|
|
|
|
A `@Component` that needs one feature flag does not benefit from a properties type. The type
|
|
would exist to hold one field and would be injected in one place.
|
|
|
|
The line is roughly: if you would name the type after the group of settings and the name would
|
|
be meaningful, use binding. If you would have to invent a name, use `@Value`.
|
|
|
|
## Reading someone else's property
|
|
|
|
`@Value("${server.port}")` reads a property owned by Spring Boot. Declaring your own type for
|
|
it would imply you own it.
|
|
|
|
## What is *not* a good reason
|
|
|
|
- **"It's less code."** For one property, marginally. For four, the properties type is
|
|
shorter and it is also checked.
|
|
- **"I need a default."** Both support defaults.
|
|
- **"@Value is faster."** Neither is measurable next to a database call, and both happen once
|
|
at startup.
|
|
- **"Relaxed binding doesn't work with @Value."** Inside Spring Boot, it does —
|
|
[chapter 2](02-relaxed-binding.md).
|