@Value
@Value injects a value from the configuration, or the result of an expression, into a constructor parameter or field of a bean.
Why use it
A bean often needs one or two settings: a port, a URL, a timeout, a feature switch. You do not want them hard-coded, and you do not want to parse config files yourself. @Value reads the setting from the environment and converts it to the type of the parameter.
${key}is replaced by the propertykey.${key:default}usesdefaultwhen the property is not set.#{...}is a SpEL expression. It can do arithmetic and read other beans.- The result is converted to the target type:
int,bool,Duration,List<String>,Resource, and so on.
Use it for a few independent settings. When a feature has several related settings under one prefix, a @ConfigurationProperties class is clearer. When the key is only known at run time, read the Environment instead.
Example
# lib/resources/application.properties
shop.name=NEON Books
shop.delivery-time=2d
shop.tags=books,comics,games
shop.max-basket-size=20
import 'package:spring_core_dart/spring_core_dart.dart';
@Service()
class Shop {
Shop(
// Raw strings (r'...'), so Dart does not read `$` as interpolation.
@Value(r'${shop.name}') this.name,
// `2d` in the file becomes Duration(days: 2).
@Value(r'${shop.delivery-time}') this.deliveryTime,
// 8080 when `shop.port` is not set anywhere.
@Value(r'${shop.port:8080}') this.port,
// A nullable target gets null when the property is missing.
@Value(r'${shop.motto}') this.motto,
);
final String name;
final Duration deliveryTime;
final int port;
final String? motto;
// A comma-separated value becomes a list.
@Value(r'${shop.tags}')
late final List<String> tags;
// SpEL: a placeholder inside an expression, then arithmetic.
@Value(r'#{${shop.max-basket-size} * 2}')
late final int warehouseLimit;
}
// SpEL can also read another bean by name: here the `shopProperties` bean
// (a @ConfigurationProperties class, which is introspected).
@Value('#{shopProperties.name.toUpperCase()}')
late final String banner;
// A location string becomes a Resource, read through the context's
// resource loader.
@Value('resources:templates/welcome.txt')
late final Resource welcomeTemplate;
What happens at startup:
- A non-nullable target without a value and without a default fails the start, with a message that names the key.
- A value that cannot be converted (
port=abcfor anint) fails the start too. - A
conversionServicebean, if you declare one, is used for the conversion. See ConversionService.
Parameters
| Name | Type | Default | Meaning |
|---|---|---|---|
value |
String |
required | Text with ${...} placeholders and/or #{...} expressions. Plain text is used as is. |
In Spring (Java)
@Service
class Shop {
Shop(@Value("${shop.name}") String name,
@Value("${shop.port:8080}") int port) { ... }
@Value("${shop.tags}") List<String> tags;
@Value("#{shopProperties.name.toUpperCase()}") String banner;
}
Differences that matter:
- In Dart, write the value as a raw string (
r'${shop.name}'). A normal string'${...}'is Dart string interpolation and does not compile as intended. - An optional value is a nullable type (
String?), not${x:#{null}}. - Spring checks lazy beans only when they are first used. Here
refresh()also checks the placeholders of lazy beans, so a missing key fails at startup. - SpEL reads only classes that have introspection metadata (
@Introspected, or classes that get it automatically such as@ConfigurationProperties). There is no reflection.