We have observed a performance regression (~9–10 seconds delay) during the Spring context refresh phase after upgrading our application from Spring 6.1.21 to Spring 6.2.11. There are over 50K beans in the ApplicationContext.
Steps to Reproduce:
- Start application using Spring 6.1.21 – observe normal startup time.
- Change only the Spring version to 6.2.11 – observe ~9–10 seconds delay during the refresh phase.
- The issue is consistently reproducible by switching between these two versions.
Environment:
- Spring Framework: 6.1.21 (baseline) vs. 6.2.11 (regression)
- Local benchmark using JMH (see Results section below)
- No other code changes between versions
Observed Behavior (Spring 6.2):
Multiple thread dumps taken during the refresh phase show the main thread consistently stuck in: - PlaceholderConfigurerSupport.doProcessProperties - PropertyPlaceholderHelper - PlaceholderParser
Expected Behavior (Spring 6.1):
- Startup completes without delay.
- Thread traces show smooth initialization and no significant time spent in property placeholder resolution.
Analysis:
- The extended time in Spring 6.2 appears related to property placeholder resolution becoming a performance bottleneck.
- This behavior was not present in 6.1 and is isolated to property processing logic during context initialization.
- See the following from Spring 6.2 release notes:
The parser for property placeholders has been completely rewritten to be as lenient as possible. As a result, certain constructs that previously worked by accident rather than by design are no longer possible.
Benchmark Setup:
Created a local benchmark repo using JMH to isolate the issue and confirm the regression.
Results:
=== Spring 6.1 Results ===
Benchmark (propertyCount) Mode Cnt Score Error Units
SpringPropertyResolutionBenchmark.benchmarkBatchPropertyResolution 10000 avgt 15 5.371 ± 0.124 us/op
SpringPropertyResolutionBenchmark.benchmarkComplexPropertyResolution 10000 avgt 15 13.733 ± 0.138 us/op
SpringPropertyResolutionBenchmark.benchmarkNestedPropertyResolution 10000 avgt 15 11.659 ± 0.123 us/op
SpringPropertyResolutionBenchmark.benchmarkPropertyPlaceholderHelper 10000 avgt 15 11.875 ± 0.152 us/op
SpringPropertyResolutionBenchmark.benchmarkSimplePropertyResolution 10000 avgt 15 5.074 ± 0.103 us/op
=== Spring 6.2 Results ===
Benchmark (propertyCount) Mode Cnt Score Error Units
SpringPropertyResolutionBenchmark.benchmarkBatchPropertyResolution 10000 avgt 15 8.391 ± 0.171 us/op
SpringPropertyResolutionBenchmark.benchmarkComplexPropertyResolution 10000 avgt 15 26.490 ± 0.730 us/op
SpringPropertyResolutionBenchmark.benchmarkNestedPropertyResolution 10000 avgt 15 20.151 ± 0.315 us/op
SpringPropertyResolutionBenchmark.benchmarkPropertyPlaceholderHelper 10000 avgt 15 23.800 ± 0.412 us/op
SpringPropertyResolutionBenchmark.benchmarkSimplePropertyResolution 10000 avgt 15 8.015 ± 0.078 us/op
Comment From: github-actions[bot]
Fixed via 449b85f446b390983931fe816bb33138f3ad146a
Comment From: jhoeller
Thanks for raising this, @rahulsh1 !
I've revised the PlaceholderParser implementation to avoid overhead for parsing plain values and simple placeholders, as far as possible. This brings the pure parser overhead in 6.2.12 down to ~20% compared to placeholder resolution performance in 6.1 (whereas plain parsing was in the ballpark of 3-4 times slower before). I hope that is good enough even for large-scale usage.
FWIW the remaining overhead is hard to optimize further since the flexibility and correctness of the re-implemented parser in 6.2 requires some additional state management.
These changes are available in the latest 6.2.12 snapshot now (https://repo.spring.io/snapshot). Please give it an early try!
Comment From: rahulsh1
Thanks for the quick response and prompt fix—really appreciate it! Most (90+%) of our usages are simple placeholders. Will give a try and update on the results.
Comment From: rahulsh1
No longer seeing the above regression with the fix. The timings for the refresh phase are back to what they were with Spring 6.1. Ran the JMH benchmark as well, the results seem to be much better too. Thanks!
=== Spring 6.1 Results ===
Benchmark (propertyCount) Mode Cnt Score Error Units
SpringPropertyResolutionBenchmark.benchmarkBatchPropertyResolution 10000 avgt 15 5.381 ± 0.128 us/op
SpringPropertyResolutionBenchmark.benchmarkComplexPropertyResolution 10000 avgt 15 13.748 ± 0.166 us/op
SpringPropertyResolutionBenchmark.benchmarkNestedPropertyResolution 10000 avgt 15 11.609 ± 0.173 us/op
SpringPropertyResolutionBenchmark.benchmarkPropertyPlaceholderHelper 10000 avgt 15 12.109 ± 0.331 us/op
SpringPropertyResolutionBenchmark.benchmarkSimplePropertyResolution 10000 avgt 15 5.106 ± 0.091 us/op
=== Spring 6.2 Results ===
Benchmark (propertyCount) Mode Cnt Score Error Units
SpringPropertyResolutionBenchmark.benchmarkBatchPropertyResolution 10000 avgt 15 5.079 ± 0.044 us/op
SpringPropertyResolutionBenchmark.benchmarkComplexPropertyResolution 10000 avgt 15 17.135 ± 0.465 us/op
SpringPropertyResolutionBenchmark.benchmarkNestedPropertyResolution 10000 avgt 15 14.194 ± 0.464 us/op
SpringPropertyResolutionBenchmark.benchmarkPropertyPlaceholderHelper 10000 avgt 15 16.600 ± 0.734 us/op
SpringPropertyResolutionBenchmark.benchmarkSimplePropertyResolution 10000 avgt 15 5.015 ± 0.111 us/op