Unlock the Full Power of Spring’s @Value: Tips, Tricks, and Common Pitfalls
This article provides a comprehensive guide to Spring’s @Value annotation, covering basic usage, property naming, handling Unicode and encoding issues, default values, static fields, arrays, collections, EL expressions, bean injection, and the differences between ${} and #{} syntax, with practical code examples and solutions to common problems.
Preface
For Java developers, the Spring framework is familiar, offering rich APIs for daily work. The @Value annotation is a useful but often overlooked feature for injecting system property values.
1. Starting with an Example
In a
@Serviceclass, a property can be injected as follows:
<code>@Service
public class UserService {
@Value("${susan.test.userName}")
private String userName;
public String test() {
System.out.println(userName);
return userName;
}
}
</code>The property name must be wrapped in
${}and defined in
applicationContext.properties:
<code># Example
susan.test.userName=\u5f20\u4e09
</code>If the property name in
@Valuedoes not match the one in the properties file, the application fails to start.
2. Property Names
When using
@ConfigurationProperties, the field name can differ from the property name as long as the prefix is the same. For example:
<code>@Configuration
@ConfigurationProperties(prefix = "susan.test")
@Data
public class MyConfig {
private String userName;
}
</code>In the properties file the key can be
susan.test.user-name(kebab‑case) while the field is
userName. Spring maps them automatically, but this flexibility does not apply to
@Value; the names must be identical.
3. Encoding Issues
Chinese characters in
.propertiesfiles are often stored as Unicode escapes (e.g.,
\u5f20\u4e09) because Spring reads them with
ISO-8859-1, causing garbled output.
Solutions:
Manually convert the ISO‑8859‑1 bytes to UTF‑8.
Use
@PropertySourcewith an
encodingattribute (not applicable to
@Value).
Store the value as a Unicode escape.
Example of manual conversion:
<code>@Service
public class UserService {
@Value(value = "${susan.test.userName}")
private String userName;
public String test() {
String userName1 = new String(userName.getBytes(StandardCharsets.ISO_8859_1), StandardCharsets.UTF_8);
return userName1;
}
}
</code>Using Unicode escapes avoids the need for conversion code.
4. Default Values
Provide a default by appending
:inside the placeholder:
<code>@Value(value = "${susan.test.userName:susan}")
private String userName;
</code>If the property is missing, the field receives
susan. An empty default can be specified with
${property:}.
5. Static Variables
Directly annotating a static field with
@Valueresults in
null. Use a setter method to assign the static variable:
<code>@Service
public class UserService {
private static String userName;
@Value("${susan.test.userName}")
public void setUserName(String userName) {
UserService.userName = userName;
}
}
</code>6. Variable Types
6.1 Primitive Types
@Value supports all primitive types and their wrapper classes:
<code>@Value("${susan.test.a:1}")
private byte a;
@Value("${susan.test.b:100}")
private short b;
@Value("${susan.test.c:3000}")
private int c;
@Value("${susan.test.d:4000000}")
private long d;
@Value("${susan.test.e:5.2}")
private float e;
@Value("${susan.test.f:6.1}")
private double f;
@Value("${susan.test.g:false}")
private boolean g;
@Value("${susan.test.h:h}")
private char h;
</code>6.2 Arrays
Arrays are injected using comma‑separated values:
<code>@Value("${susan.test.array:1,2,3,4,5}")
private int[] array;
</code>Note that spaces are removed, so
1 2 3becomes
123.
6.3 Collections
List
Inject a
Listvia an EL expression:
<code>@Value("#{'${susan.test.list}'.split(',')}")
private List<String> list;
</code>Properties file:
<code>susan.test.list=10,11,12,13
</code>Set
<code>@Value("#{'${susan.test.set}'.split(',')}")
private Set<String> set;
</code>To provide an empty default, use the
emptycheck:
<code>@Value("#{'${susan.test.set:}'.empty ? null : '${susan.test.set:}'.split(',')}")
private Set<String> set;
</code>Map
<code>@Value("#{${susan.test.map}}")
private Map<String, String> map;
</code>Properties file example:
<code>susan.test.map={"name":"苏三","age":"18"}
</code>7. Advanced EL Usage
7.1 Bean Injection
Inject a bean directly with EL:
<code>@Value("#{roleService}")
private RoleService roleService;
</code>7.2 Accessing Bean Members
Inject constants, fields, methods, and static methods:
<code>@Value("#{roleService.DEFAULT_AGE}")
private int myAge;
@Value("#{roleService.id}")
private int id;
@Value("#{roleService.getRoleName()}")
private String myRoleName;
@Value("#{roleService.getParentId()}")
private String myParentId;
</code>7.3 Static Classes
Use
T()to call static members:
<code>@Value("#{T(java.io.File).separator}")
private String path;
@Value("#{T(java.lang.Math).random()}")
private double randomValue;
</code>7.4 Logical Operations
Combine values, perform conditionals, and ternary expressions:
<code>@Value("#{roleService.roleName + '' + roleService.DEFAULT_AGE}")
private String combined;
@Value("#{roleService.DEFAULT_AGE > 16 and roleService.roleName.equals('苏三')}")
private boolean condition;
@Value("#{roleService.DEFAULT_AGE > 16 ? roleService.roleName : '苏三'}")
private String ternaryResult;
</code>8. Difference Between ${} and #{}
${}retrieves values from configuration files, optionally providing defaults with
:. Missing properties without defaults cause startup failures.
#{}evaluates Spring EL expressions, allowing bean injection, static method calls, and complex logic.
macrozheng
Dedicated to Java tech sharing and dissecting top open-source projects. Topics include Spring Boot, Spring Cloud, Docker, Kubernetes and more. Author’s GitHub project “mall” has 50K+ stars.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.