From 9a09c2842b329e086f5c35f0539766278200bca6 Mon Sep 17 00:00:00 2001 From: Junggi Kim Date: Thu, 10 Sep 2026 18:11:22 +0900 Subject: [PATCH] Avoid rebuilding metadata maps when computing the changelog Changelog.computeDifferences() called ConfigurationMetadataRepository.getAllProperties() from inside its main loop. The default repository implementation builds a new map each time that method is called, so the new version's properties were rebuilt once per property of the old version. The ids that had already been seen were also tracked in an ArrayList, turning each membership check into a linear scan. Read the properties of each repository once and use the old properties map itself to detect the properties that have been added. Computing the changelog between Spring Boot 3.4.0 and 3.5.0 (2,498 and 2,555 properties) drops from 203ms to 0.5ms and the generator's peak memory from 302MB to 91MB. The generated asciidoc is byte for byte identical. See gh-51655 Signed-off-by: Junggi Kim --- .../changelog/Changelog.java | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/configuration-metadata/spring-boot-configuration-metadata-changelog-generator/src/main/java/org/springframework/boot/configurationmetadata/changelog/Changelog.java b/configuration-metadata/spring-boot-configuration-metadata-changelog-generator/src/main/java/org/springframework/boot/configurationmetadata/changelog/Changelog.java index df46b7fb7e2..d9f3738f9e6 100644 --- a/configuration-metadata/spring-boot-configuration-metadata-changelog-generator/src/main/java/org/springframework/boot/configurationmetadata/changelog/Changelog.java +++ b/configuration-metadata/spring-boot-configuration-metadata-changelog-generator/src/main/java/org/springframework/boot/configurationmetadata/changelog/Changelog.java @@ -18,6 +18,7 @@ package org.springframework.boot.configurationmetadata.changelog; import java.util.ArrayList; import java.util.List; +import java.util.Map; import org.springframework.boot.configurationmetadata.ConfigurationMetadataProperty; import org.springframework.boot.configurationmetadata.ConfigurationMetadataRepository; @@ -34,6 +35,7 @@ import org.springframework.boot.configurationmetadata.Deprecation.Level; * @author Andy Wilkinson * @author Phillip Webb * @author Yoobin Yoon + * @author Junggi Kim */ record Changelog(String oldVersionNumber, String newVersionNumber, List differences) { @@ -44,19 +46,18 @@ record Changelog(String oldVersionNumber, String newVersionNumber, List computeDifferences(ConfigurationMetadataRepository oldMetadata, ConfigurationMetadataRepository newMetadata) { - List seenIds = new ArrayList<>(); + Map oldProperties = oldMetadata.getAllProperties(); + Map newProperties = newMetadata.getAllProperties(); List differences = new ArrayList<>(); - for (ConfigurationMetadataProperty oldProperty : oldMetadata.getAllProperties().values()) { - String id = oldProperty.getId(); - seenIds.add(id); - ConfigurationMetadataProperty newProperty = newMetadata.getAllProperties().get(id); + for (ConfigurationMetadataProperty oldProperty : oldProperties.values()) { + ConfigurationMetadataProperty newProperty = newProperties.get(oldProperty.getId()); Difference difference = Difference.compute(oldProperty, newProperty); if (difference != null) { differences.add(difference); } } - for (ConfigurationMetadataProperty newProperty : newMetadata.getAllProperties().values()) { - if (!seenIds.contains(newProperty.getId())) { + for (ConfigurationMetadataProperty newProperty : newProperties.values()) { + if (!oldProperties.containsKey(newProperty.getId())) { if (!newProperty.isDeprecated()) { differences.add(new Difference(DifferenceType.ADDED, null, newProperty)); }