AutoConfigurationSorter Class — spring-boot Architecture
Architecture documentation for the AutoConfigurationSorter class in AutoConfigurationSorter.java from the spring-boot codebase.
Entity Profile
Source Code
core/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/AutoConfigurationSorter.java lines 48–297
class AutoConfigurationSorter {
private final MetadataReaderFactory metadataReaderFactory;
private final @Nullable AutoConfigurationMetadata autoConfigurationMetadata;
private final @Nullable UnaryOperator<String> replacementMapper;
AutoConfigurationSorter(MetadataReaderFactory metadataReaderFactory,
@Nullable AutoConfigurationMetadata autoConfigurationMetadata,
@Nullable UnaryOperator<String> replacementMapper) {
Assert.notNull(metadataReaderFactory, "'metadataReaderFactory' must not be null");
this.metadataReaderFactory = metadataReaderFactory;
this.autoConfigurationMetadata = autoConfigurationMetadata;
this.replacementMapper = replacementMapper;
}
List<String> getInPriorityOrder(Collection<String> classNames) {
// Initially sort alphabetically
List<String> alphabeticallyOrderedClassNames = new ArrayList<>(classNames);
Collections.sort(alphabeticallyOrderedClassNames);
// Then sort by order
AutoConfigurationClasses classes = new AutoConfigurationClasses(this.metadataReaderFactory,
this.autoConfigurationMetadata, alphabeticallyOrderedClassNames);
List<String> orderedClassNames = new ArrayList<>(classNames);
Collections.sort(orderedClassNames);
orderedClassNames.sort((o1, o2) -> {
int i1 = classes.get(o1).getOrder();
int i2 = classes.get(o2).getOrder();
return Integer.compare(i1, i2);
});
// Then respect @AutoConfigureBefore @AutoConfigureAfter
orderedClassNames = sortByAnnotation(classes, orderedClassNames);
return orderedClassNames;
}
private List<String> sortByAnnotation(AutoConfigurationClasses classes, List<String> classNames) {
List<String> toSort = new ArrayList<>(classNames);
toSort.addAll(classes.getAllNames());
Set<String> sorted = new LinkedHashSet<>();
Set<String> processing = new LinkedHashSet<>();
while (!toSort.isEmpty()) {
doSortByAfterAnnotation(classes, toSort, sorted, processing, null);
}
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);
}
processing.add(current);
Set<String> afters = new TreeSet<>(Comparator.comparing(toSort::indexOf));
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);
}
}
processing.remove(current);
sorted.add(current);
}
private void checkForCycles(Set<String> processing, String current, String after) {
Assert.state(!processing.contains(after),
() -> "AutoConfigure cycle detected between " + current + " and " + after);
}
private class AutoConfigurationClasses {
private final Map<String, AutoConfigurationClass> classes = new LinkedHashMap<>();
AutoConfigurationClasses(MetadataReaderFactory metadataReaderFactory,
@Nullable AutoConfigurationMetadata autoConfigurationMetadata, Collection<String> classNames) {
addToClasses(metadataReaderFactory, autoConfigurationMetadata, classNames, true);
}
Set<String> getAllNames() {
return this.classes.keySet();
}
private void addToClasses(MetadataReaderFactory metadataReaderFactory,
@Nullable AutoConfigurationMetadata autoConfigurationMetadata, Collection<String> classNames,
boolean required) {
for (String className : classNames) {
if (!this.classes.containsKey(className)) {
AutoConfigurationClass autoConfigurationClass = new AutoConfigurationClass(className,
metadataReaderFactory, autoConfigurationMetadata);
boolean available = autoConfigurationClass.isAvailable();
if (required || available) {
this.classes.put(className, autoConfigurationClass);
}
if (available) {
addToClasses(metadataReaderFactory, autoConfigurationMetadata,
autoConfigurationClass.getBefore(), false);
addToClasses(metadataReaderFactory, autoConfigurationMetadata,
autoConfigurationClass.getAfter(), false);
}
}
}
}
AutoConfigurationClass get(String className) {
AutoConfigurationClass autoConfigurationClass = this.classes.get(className);
Assert.state(autoConfigurationClass != null, "'autoConfigurationClass' must not be null");
return autoConfigurationClass;
}
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);
}
});
return classesRequestedAfter;
}
}
private class AutoConfigurationClass {
private final String className;
private final MetadataReaderFactory metadataReaderFactory;
private final @Nullable AutoConfigurationMetadata autoConfigurationMetadata;
private volatile @Nullable AnnotationMetadata annotationMetadata;
private volatile @Nullable Set<String> before;
private volatile @Nullable Set<String> after;
AutoConfigurationClass(String className, MetadataReaderFactory metadataReaderFactory,
@Nullable AutoConfigurationMetadata autoConfigurationMetadata) {
this.className = className;
this.metadataReaderFactory = metadataReaderFactory;
this.autoConfigurationMetadata = autoConfigurationMetadata;
}
boolean isAvailable() {
try {
if (!wasProcessed()) {
getAnnotationMetadata();
}
return true;
}
catch (Exception ex) {
return false;
}
}
Set<String> getBefore() {
Set<String> before = this.before;
if (before == null) {
before = getClassNames("AutoConfigureBefore", AutoConfigureBefore.class);
this.before = before;
}
return before;
}
Set<String> getAfter() {
Set<String> after = this.after;
if (after == null) {
after = getClassNames("AutoConfigureAfter", AutoConfigureAfter.class);
this.after = after;
}
return after;
}
private Set<String> getClassNames(String metadataKey, Class<? extends Annotation> annotation) {
Set<String> annotationValue = wasProcessed() ? getSet(metadataKey) : getAnnotationValue(annotation);
return applyReplacements(annotationValue);
}
private Set<String> getSet(String metadataKey) {
Assert.state(this.autoConfigurationMetadata != null, "'autoConfigurationMetadata' must not be null");
return this.autoConfigurationMetadata.getSet(this.className, metadataKey, Collections.emptySet());
}
private Set<String> applyReplacements(Set<String> values) {
if (AutoConfigurationSorter.this.replacementMapper == null) {
return values;
}
Set<String> replaced = new LinkedHashSet<>(values);
for (String value : values) {
replaced.add(AutoConfigurationSorter.this.replacementMapper.apply(value));
}
return replaced;
}
private int getOrder() {
if (wasProcessed()) {
Assert.state(this.autoConfigurationMetadata != null, "'autoConfigurationMetadata' must not be null");
return this.autoConfigurationMetadata.getInteger(this.className, "AutoConfigureOrder",
AutoConfigureOrder.DEFAULT_ORDER);
}
Map<String, @Nullable Object> attributes = getAnnotationMetadata()
.getAnnotationAttributes(AutoConfigureOrder.class.getName());
if (attributes != null) {
Integer value = (Integer) attributes.get("value");
Assert.state(value != null, "'value' must not be null");
return value;
}
return AutoConfigureOrder.DEFAULT_ORDER;
}
private boolean wasProcessed() {
return (this.autoConfigurationMetadata != null
&& this.autoConfigurationMetadata.wasProcessed(this.className));
}
private Set<String> getAnnotationValue(Class<?> annotation) {
Map<String, @Nullable Object> attributes = getAnnotationMetadata()
.getAnnotationAttributes(annotation.getName(), true);
if (attributes == null) {
return Collections.emptySet();
}
Set<String> result = new LinkedHashSet<>();
String[] value = (String[]) attributes.get("value");
String[] name = (String[]) attributes.get("name");
Assert.state(value != null, "'value' must not be null");
Assert.state(name != null, "'name' must not be null");
Collections.addAll(result, value);
Collections.addAll(result, name);
return result;
}
private AnnotationMetadata getAnnotationMetadata() {
AnnotationMetadata annotationMetadata = this.annotationMetadata;
if (annotationMetadata == null) {
try {
MetadataReader metadataReader = this.metadataReaderFactory.getMetadataReader(this.className);
annotationMetadata = metadataReader.getAnnotationMetadata();
this.annotationMetadata = annotationMetadata;
}
catch (IOException ex) {
throw new IllegalStateException("Unable to read meta-data for class " + this.className, ex);
}
}
return annotationMetadata;
}
}
}
Source
Analyze Your Own Codebase
Get architecture documentation, dependency graphs, and domain analysis for your codebase in minutes.
Try Supermodel Free