mirror of
https://github.com/spring-projects/spring-boot.git
synced 2026-09-29 21:59:02 +00:00
Merge pull request #51867 from aalsanie
Closes gh-51867 * pr/51867: Polish 'Improve auto-configuration sorting performance' Improve auto-configuration sorting performance
This commit is contained in:
+23
-20
@@ -77,34 +77,35 @@ class AutoConfigurationSorter {
|
||||
return Integer.compare(i1, i2);
|
||||
});
|
||||
// Then respect @AutoConfigureBefore @AutoConfigureAfter
|
||||
orderedClassNames = sortByAnnotation(classes, orderedClassNames);
|
||||
orderedClassNames = sortByAnnotation(new LinkedHashSet<>(orderedClassNames), classes);
|
||||
return orderedClassNames;
|
||||
}
|
||||
|
||||
private List<String> sortByAnnotation(AutoConfigurationClasses classes, List<String> classNames) {
|
||||
List<String> toSort = new ArrayList<>(classNames);
|
||||
toSort.addAll(classes.getAllNames());
|
||||
private List<String> sortByAnnotation(Set<String> classNames, AutoConfigurationClasses classes) {
|
||||
Map<String, Integer> sortOrder = new LinkedHashMap<>();
|
||||
classNames.forEach((className) -> sortOrder.putIfAbsent(className, sortOrder.size()));
|
||||
classes.getAllNames().forEach((className) -> sortOrder.putIfAbsent(className, sortOrder.size()));
|
||||
Set<String> sorted = new LinkedHashSet<>();
|
||||
Set<String> processing = new LinkedHashSet<>();
|
||||
while (!toSort.isEmpty()) {
|
||||
doSortByAfterAnnotation(classes, toSort, sorted, processing, null);
|
||||
for (String className : sortOrder.keySet()) {
|
||||
doSortByAfterAnnotation(classes, sortOrder, sorted, processing, className);
|
||||
}
|
||||
sorted.retainAll(classNames);
|
||||
return new ArrayList<>(sorted);
|
||||
}
|
||||
|
||||
private void doSortByAfterAnnotation(AutoConfigurationClasses classes, List<String> toSort, Set<String> sorted,
|
||||
Set<String> processing, @Nullable String current) {
|
||||
if (current == null) {
|
||||
current = toSort.remove(0);
|
||||
private void doSortByAfterAnnotation(AutoConfigurationClasses classes, Map<String, Integer> sortOrder,
|
||||
Set<String> sorted, Set<String> processing, String current) {
|
||||
if (sorted.contains(current)) {
|
||||
return;
|
||||
}
|
||||
processing.add(current);
|
||||
Set<String> afters = new TreeSet<>(Comparator.comparing(toSort::indexOf));
|
||||
Set<String> afters = new TreeSet<>(Comparator.comparingInt((String name) -> sortOrder.getOrDefault(name, -1)));
|
||||
afters.addAll(classes.getClassesRequestedAfter(current));
|
||||
for (String after : afters) {
|
||||
checkForCycles(processing, current, after);
|
||||
if (!sorted.contains(after) && toSort.contains(after)) {
|
||||
doSortByAfterAnnotation(classes, toSort, sorted, processing, after);
|
||||
if (sortOrder.containsKey(after)) {
|
||||
doSortByAfterAnnotation(classes, sortOrder, sorted, processing, after);
|
||||
}
|
||||
}
|
||||
processing.remove(current);
|
||||
@@ -120,6 +121,8 @@ class AutoConfigurationSorter {
|
||||
|
||||
private final Map<String, AutoConfigurationClass> classes = new LinkedHashMap<>();
|
||||
|
||||
private final Map<String, Set<String>> classesRequestedAfter = new LinkedHashMap<>();
|
||||
|
||||
AutoConfigurationClasses(MetadataReaderFactory metadataReaderFactory,
|
||||
@Nullable AutoConfigurationMetadata autoConfigurationMetadata, Collection<String> classNames) {
|
||||
addToClasses(metadataReaderFactory, autoConfigurationMetadata, classNames, true);
|
||||
@@ -141,8 +144,12 @@ class AutoConfigurationSorter {
|
||||
this.classes.put(className, autoConfigurationClass);
|
||||
}
|
||||
if (available) {
|
||||
addToClasses(metadataReaderFactory, autoConfigurationMetadata,
|
||||
autoConfigurationClass.getBefore(), false);
|
||||
Set<String> before = autoConfigurationClass.getBefore();
|
||||
for (String name : before) {
|
||||
this.classesRequestedAfter.computeIfAbsent(name, (key) -> new LinkedHashSet<>())
|
||||
.add(className);
|
||||
}
|
||||
addToClasses(metadataReaderFactory, autoConfigurationMetadata, before, false);
|
||||
addToClasses(metadataReaderFactory, autoConfigurationMetadata,
|
||||
autoConfigurationClass.getAfter(), false);
|
||||
}
|
||||
@@ -158,11 +165,7 @@ class AutoConfigurationSorter {
|
||||
|
||||
Set<String> getClassesRequestedAfter(String className) {
|
||||
Set<String> classesRequestedAfter = new LinkedHashSet<>(get(className).getAfter());
|
||||
this.classes.forEach((name, autoConfigurationClass) -> {
|
||||
if (autoConfigurationClass.getBefore().contains(className)) {
|
||||
classesRequestedAfter.add(name);
|
||||
}
|
||||
});
|
||||
classesRequestedAfter.addAll(this.classesRequestedAfter.getOrDefault(className, Collections.emptySet()));
|
||||
return classesRequestedAfter;
|
||||
}
|
||||
|
||||
|
||||
+32
@@ -188,6 +188,38 @@ class AutoConfigurationSorterTests {
|
||||
assertThat(actual).containsExactly(B, A);
|
||||
}
|
||||
|
||||
@Test
|
||||
void orderIsStableForLargerMixedGraph() {
|
||||
List<String> actual = getInPriorityOrder(LOWEST, HIGHEST, DEFAULT, A, A2, B, C, E, W, W2, X, Y, Z);
|
||||
assertThat(actual).containsExactly(HIGHEST, C, E, W, W2, B, A, A2, Z, Y, X, DEFAULT, LOWEST);
|
||||
}
|
||||
|
||||
@Test
|
||||
void orderIsStableForLargerMixedGraphWithReversedInput() {
|
||||
List<String> actual = getInPriorityOrder(Z, Y, X, W2, W, E, C, B, A2, A, DEFAULT, HIGHEST, LOWEST);
|
||||
assertThat(actual).containsExactly(HIGHEST, C, E, W, W2, B, A, A2, Z, Y, X, DEFAULT, LOWEST);
|
||||
}
|
||||
|
||||
@Test
|
||||
void duplicateInputDoesNotChangeResult() {
|
||||
List<String> actual = getInPriorityOrder(A, B, C, B, A, C);
|
||||
assertThat(actual).containsExactly(C, B, A);
|
||||
}
|
||||
|
||||
@Test
|
||||
void transitivelyDiscoveredClassesAreNotIncludedInResult() {
|
||||
List<String> actual = getInPriorityOrder(A, C);
|
||||
assertThat(actual).containsExactly(C, A);
|
||||
}
|
||||
|
||||
@Test
|
||||
void cycleReportsSameClasses() {
|
||||
this.sorter = new AutoConfigurationSorter(new CachingMetadataReaderFactory(), this.autoConfigurationMetadata,
|
||||
REPLACEMENT_MAPPER);
|
||||
assertThatIllegalStateException().isThrownBy(() -> getInPriorityOrder(A, B, C, D))
|
||||
.withMessage("AutoConfigure cycle detected between " + D + " and " + A);
|
||||
}
|
||||
|
||||
@Test
|
||||
void byAutoConfigureAfterWithCycle() {
|
||||
this.sorter = new AutoConfigurationSorter(new CachingMetadataReaderFactory(), this.autoConfigurationMetadata,
|
||||
|
||||
Reference in New Issue
Block a user