Keywords: Spring Boot | Property Placeholder | Maven Resource Filtering
Abstract: This article provides an in-depth analysis of the 'Could not resolve placeholder' error in Spring Boot applications, focusing on the issue where application.properties files are not properly read when running on embedded Tomcat servers. Through detailed examination of Maven resource filtering mechanisms and Spring property resolution processes, it offers comprehensive solutions and best practice recommendations to help developers fundamentally understand and resolve such configuration issues.
Problem Background and Phenomenon Analysis
During Spring Boot application development, developers frequently encounter property placeholder resolution failures. The specific manifestation occurs when running on embedded Tomcat servers, where Spring cannot resolve placeholders in @Value("${propertyName}") annotations, even though the corresponding properties are correctly defined in the application.properties file.
Error Scenario Reproduction
A typical error scenario is as follows: when starting the application using the mvn clean install spring-boot:run command, the console outputs the following error stack trace:
Caused by: java.lang.IllegalArgumentException: Could not resolve placeholder 'language' in string value "${language}"
at org.springframework.util.PropertyPlaceholderHelper.parseStringValue(PropertyPlaceholderHelper.java:174)
...
The corresponding code configuration is:
@Value("${language}")
private String language;
While the application.properties file contains:
language=java
logging.level.org.springframework=TRACE
Root Cause Investigation
The core issue lies in the resource file processing mechanism during Maven build processes. When using the spring-boot:run goal, Maven does not automatically process property files in resource directories, causing Spring Boot to be unable to find the corresponding configuration files in the classpath.
Spring Boot's property resolution mechanism follows a specific loading order: command line arguments, JNDI properties, JVM system properties, operating system environment variables, random properties, external application configuration files, internal application configuration files, etc. When running on embedded servers, if resource files are not properly packaged into the classpath, property resolution will fail.
Solution Implementation
By configuring resource filtering in the pom.xml file, property files can be properly processed:
<build>
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
<includes>
<include>**/*.properties</include>
</includes>
</resource>
</resources>
</build>
This configuration serves the following purposes:
<directory>specifies the directory containing resource files<filtering>true</filtering>enables resource filtering, allowing the use of Maven properties in property files<includes>specifies the file types to be processed
Technical Principle Deep Dive
Spring's property placeholder resolution mechanism is implemented based on the PropertySourcesPlaceholderConfigurer class. This class is responsible for resolving placeholders from multiple property sources, including environment variables, system properties, configuration files, etc.
When the Spring container starts, it creates a PropertySourcesPlaceholderConfigurer instance that:
- Collects all available property sources
- Establishes a property resolution chain in priority order
- Replaces all
${...}format placeholders during bean initialization
In embedded server scenarios, if resource files are not properly included in the classpath, the property resolution chain will lack corresponding property sources, causing placeholder resolution to fail.
Alternative Approaches and Best Practices
In addition to resource filtering configuration, the following alternative approaches can be considered:
1. Using Default Values
@Value("${language:java}")
private String language;
While this approach can avoid runtime errors, it masks configuration issues and is not recommended for production environments.
2. Environment Variable Configuration
Spring Boot supports setting property values through environment variables, with environment variable names following specific naming conventions:
- Replace dots with underscores
- Convert to uppercase letters
- For example: the environment variable for the
languageproperty isLANGUAGE
3. IDE Cache Cleaning
In some integrated development environments, cache issues may cause configuration reading abnormalities. You can try:
- IntelliJ IDEA:
Build → Rebuild ProjectorFile → Invalidate Caches / Restart - Eclipse: Clean the project and rebuild
Configuration Verification and Debugging Techniques
To verify whether configurations are correctly effective, the following debugging methods can be employed:
1. Enable Detailed Logging
logging.level.org.springframework=TRACE
logging.level.org.springframework.core.env=DEBUG
2. Check Classpath
Output classpath information during application startup to confirm whether resource files are properly included:
System.out.println("Classpath: " + System.getProperty("java.class.path"));
3. Property Source Inspection
Programmatically check all available property sources:
@Autowired
private Environment env;
public void checkProperties() {
System.out.println("Available property sources:");
for (PropertySource<?> source : ((AbstractEnvironment) env).getPropertySources()) {
System.out.println(source.getName());
}
}
Summary and Recommendations
The fundamental cause of Spring Boot property resolution failure issues lies in the inconsistency between build tool configurations and runtime environments. By correctly configuring Maven resource filtering, property files can be properly loaded when running on embedded servers. It is recommended that developers establish comprehensive build configurations early in the project to avoid inconsistent behavior across development, testing, and production environments.
Best practices include:
- Unifying build configurations across all environments
- Explicitly configuring resource processing in
pom.xml - Establishing property configuration verification mechanisms
- Using configuration centers or environment variables to manage sensitive configurations
By deeply understanding Spring Boot's property resolution mechanism and Maven's build process, developers can better diagnose and resolve similar configuration issues, improving application stability and maintainability.