Optimize AutoConfigurationSorter
Optimize `AutoConfigurationSorter` by used properties generated by the annotation processor whenever possible. The removes the need for each candidate class to be ASM parsed just to access the order annotations. See gh-7573
This commit is contained in:
parent
1cbda9bd60
commit
02641a8207
|
|
@ -76,19 +76,21 @@ public class AutoConfigurationImportSelector
|
|||
private ResourceLoader resourceLoader;
|
||||
|
||||
@Override
|
||||
public String[] selectImports(AnnotationMetadata metadata) {
|
||||
if (!isEnabled(metadata)) {
|
||||
public String[] selectImports(AnnotationMetadata annotationMetadata) {
|
||||
if (!isEnabled(annotationMetadata)) {
|
||||
return NO_IMPORTS;
|
||||
}
|
||||
try {
|
||||
AnnotationAttributes attributes = getAttributes(metadata);
|
||||
List<String> configurations = getCandidateConfigurations(metadata,
|
||||
AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader
|
||||
.loadMetadata(this.beanClassLoader);
|
||||
AnnotationAttributes attributes = getAttributes(annotationMetadata);
|
||||
List<String> configurations = getCandidateConfigurations(annotationMetadata,
|
||||
attributes);
|
||||
configurations = removeDuplicates(configurations);
|
||||
Set<String> exclusions = getExclusions(metadata, attributes);
|
||||
configurations = sort(configurations, autoConfigurationMetadata);
|
||||
Set<String> exclusions = getExclusions(annotationMetadata, attributes);
|
||||
checkExcludedClasses(configurations, exclusions);
|
||||
configurations.removeAll(exclusions);
|
||||
configurations = sort(configurations);
|
||||
fireAutoConfigurationImportListeners(configurations, exclusions);
|
||||
return configurations.toArray(new String[configurations.size()]);
|
||||
}
|
||||
|
|
@ -224,9 +226,10 @@ public class AutoConfigurationImportSelector
|
|||
return (Arrays.asList(exclude == null ? new String[0] : exclude));
|
||||
}
|
||||
|
||||
private List<String> sort(List<String> configurations) throws IOException {
|
||||
configurations = new AutoConfigurationSorter(getMetadataReaderFactory())
|
||||
.getInPriorityOrder(configurations);
|
||||
private List<String> sort(List<String> configurations,
|
||||
AutoConfigurationMetadata autoConfigurationMetadata) throws IOException {
|
||||
configurations = new AutoConfigurationSorter(getMetadataReaderFactory(),
|
||||
autoConfigurationMetadata).getInPriorityOrder(configurations);
|
||||
return configurations;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2012-2016 the original author or authors.
|
||||
* Copyright 2012-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
|
@ -35,8 +35,8 @@ import org.springframework.util.Assert;
|
|||
|
||||
/**
|
||||
* Sort {@link EnableAutoConfiguration auto-configuration} classes into priority order by
|
||||
* reading {@link Ordered}, {@link AutoConfigureBefore} and {@link AutoConfigureAfter}
|
||||
* annotations (without loading classes).
|
||||
* reading {@link AutoConfigureOrder}, {@link AutoConfigureBefore} and
|
||||
* {@link AutoConfigureAfter} annotations (without loading classes).
|
||||
*
|
||||
* @author Phillip Webb
|
||||
*/
|
||||
|
|
@ -44,26 +44,31 @@ class AutoConfigurationSorter {
|
|||
|
||||
private final MetadataReaderFactory metadataReaderFactory;
|
||||
|
||||
AutoConfigurationSorter(MetadataReaderFactory metadataReaderFactory) {
|
||||
private final AutoConfigurationMetadata autoConfigurationMetadata;
|
||||
|
||||
AutoConfigurationSorter(MetadataReaderFactory metadataReaderFactory,
|
||||
AutoConfigurationMetadata autoConfigurationMetadata) {
|
||||
Assert.notNull(metadataReaderFactory, "MetadataReaderFactory must not be null");
|
||||
this.metadataReaderFactory = metadataReaderFactory;
|
||||
this.autoConfigurationMetadata = autoConfigurationMetadata;
|
||||
}
|
||||
|
||||
public List<String> getInPriorityOrder(Collection<String> classNames)
|
||||
throws IOException {
|
||||
public List<String> getInPriorityOrder(Collection<String> classNames) {
|
||||
final AutoConfigurationClasses classes = new AutoConfigurationClasses(
|
||||
this.metadataReaderFactory, classNames);
|
||||
this.metadataReaderFactory, this.autoConfigurationMetadata, classNames);
|
||||
List<String> orderedClassNames = new ArrayList<String>(classNames);
|
||||
// Initially sort alphabetically
|
||||
Collections.sort(orderedClassNames);
|
||||
// Then sort by order
|
||||
Collections.sort(orderedClassNames, new Comparator<String>() {
|
||||
|
||||
@Override
|
||||
public int compare(String o1, String o2) {
|
||||
int i1 = classes.get(o1).getOrder();
|
||||
int i2 = classes.get(o2).getOrder();
|
||||
return (i1 < i2) ? -1 : (i1 > i2) ? 1 : 0;
|
||||
}
|
||||
|
||||
});
|
||||
// Then respect @AutoConfigureBefore @AutoConfigureAfter
|
||||
orderedClassNames = sortByAnnotation(classes, orderedClassNames);
|
||||
|
|
@ -104,11 +109,11 @@ class AutoConfigurationSorter {
|
|||
private final Map<String, AutoConfigurationClass> classes = new HashMap<String, AutoConfigurationClass>();
|
||||
|
||||
AutoConfigurationClasses(MetadataReaderFactory metadataReaderFactory,
|
||||
Collection<String> classNames) throws IOException {
|
||||
AutoConfigurationMetadata autoConfigurationMetadata,
|
||||
Collection<String> classNames) {
|
||||
for (String className : classNames) {
|
||||
MetadataReader metadataReader = metadataReaderFactory
|
||||
.getMetadataReader(className);
|
||||
this.classes.put(className, new AutoConfigurationClass(metadataReader));
|
||||
this.classes.put(className, new AutoConfigurationClass(className,
|
||||
metadataReaderFactory, autoConfigurationMetadata));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -132,29 +137,65 @@ class AutoConfigurationSorter {
|
|||
|
||||
private static class AutoConfigurationClass {
|
||||
|
||||
private final AnnotationMetadata metadata;
|
||||
private final String className;
|
||||
|
||||
AutoConfigurationClass(MetadataReader metadataReader) {
|
||||
this.metadata = metadataReader.getAnnotationMetadata();
|
||||
}
|
||||
private final MetadataReaderFactory metadataReaderFactory;
|
||||
|
||||
public int getOrder() {
|
||||
Map<String, Object> orderedAnnotation = this.metadata
|
||||
.getAnnotationAttributes(AutoConfigureOrder.class.getName());
|
||||
return (orderedAnnotation == null ? Ordered.LOWEST_PRECEDENCE
|
||||
: (Integer) orderedAnnotation.get("value"));
|
||||
private final AutoConfigurationMetadata autoConfigurationMetadata;
|
||||
|
||||
private AnnotationMetadata annotationMetadata;
|
||||
|
||||
private final Set<String> before;
|
||||
|
||||
private final Set<String> after;
|
||||
|
||||
AutoConfigurationClass(String className,
|
||||
MetadataReaderFactory metadataReaderFactory,
|
||||
AutoConfigurationMetadata autoConfigurationMetadata) {
|
||||
this.className = className;
|
||||
this.metadataReaderFactory = metadataReaderFactory;
|
||||
this.autoConfigurationMetadata = autoConfigurationMetadata;
|
||||
this.before = readBefore();
|
||||
this.after = readAfter();
|
||||
}
|
||||
|
||||
public Set<String> getBefore() {
|
||||
return getAnnotationValue(AutoConfigureBefore.class);
|
||||
return this.before;
|
||||
}
|
||||
|
||||
public Set<String> getAfter() {
|
||||
return this.after;
|
||||
}
|
||||
|
||||
private int getOrder() {
|
||||
if (this.autoConfigurationMetadata.wasProcessed(this.className)) {
|
||||
return this.autoConfigurationMetadata.getInteger(this.className,
|
||||
"AutoConfigureOrder", Ordered.LOWEST_PRECEDENCE);
|
||||
}
|
||||
Map<String, Object> attributes = getAnnotationMetadata()
|
||||
.getAnnotationAttributes(AutoConfigureOrder.class.getName());
|
||||
return (attributes == null ? Ordered.LOWEST_PRECEDENCE
|
||||
: (Integer) attributes.get("value"));
|
||||
}
|
||||
|
||||
private Set<String> readBefore() {
|
||||
if (this.autoConfigurationMetadata.wasProcessed(this.className)) {
|
||||
return this.autoConfigurationMetadata.getSet(this.className,
|
||||
"AutoConfigureBefore", Collections.<String>emptySet());
|
||||
}
|
||||
return getAnnotationValue(AutoConfigureBefore.class);
|
||||
}
|
||||
|
||||
private Set<String> readAfter() {
|
||||
if (this.autoConfigurationMetadata.wasProcessed(this.className)) {
|
||||
return this.autoConfigurationMetadata.getSet(this.className,
|
||||
"AutoConfigureAfter", Collections.<String>emptySet());
|
||||
}
|
||||
return getAnnotationValue(AutoConfigureAfter.class);
|
||||
}
|
||||
|
||||
private Set<String> getAnnotationValue(Class<?> annotation) {
|
||||
Map<String, Object> attributes = this.metadata
|
||||
Map<String, Object> attributes = getAnnotationMetadata()
|
||||
.getAnnotationAttributes(annotation.getName(), true);
|
||||
if (attributes == null) {
|
||||
return Collections.emptySet();
|
||||
|
|
@ -165,6 +206,21 @@ class AutoConfigurationSorter {
|
|||
return value;
|
||||
}
|
||||
|
||||
private AnnotationMetadata getAnnotationMetadata() {
|
||||
if (this.annotationMetadata == null) {
|
||||
try {
|
||||
MetadataReader metadataReader = this.metadataReaderFactory
|
||||
.getMetadataReader(this.className);
|
||||
this.annotationMetadata = metadataReader.getAnnotationMetadata();
|
||||
}
|
||||
catch (IOException ex) {
|
||||
throw new IllegalStateException(
|
||||
"Unable to read meta-data for class " + this.className, ex);
|
||||
}
|
||||
}
|
||||
return this.annotationMetadata;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2012-2016 the original author or authors.
|
||||
* Copyright 2012-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
|
@ -17,7 +17,10 @@
|
|||
package org.springframework.boot.autoconfigure;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Properties;
|
||||
import java.util.Set;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
|
|
@ -26,8 +29,12 @@ import org.junit.rules.ExpectedException;
|
|||
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.core.type.classreading.CachingMetadataReaderFactory;
|
||||
import org.springframework.core.type.classreading.MetadataReaderFactory;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
/**
|
||||
* Tests for {@link AutoConfigurationSorter}.
|
||||
|
|
@ -67,9 +74,13 @@ public class AutoConfigurationSorterTests {
|
|||
|
||||
private AutoConfigurationSorter sorter;
|
||||
|
||||
private AutoConfigurationMetadata autoConfigurationMetadata = mock(
|
||||
AutoConfigurationMetadata.class);
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
this.sorter = new AutoConfigurationSorter(new CachingMetadataReaderFactory());
|
||||
this.sorter = new AutoConfigurationSorter(new CachingMetadataReaderFactory(),
|
||||
this.autoConfigurationMetadata);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
@ -132,6 +143,56 @@ public class AutoConfigurationSorterTests {
|
|||
this.sorter.getInPriorityOrder(Arrays.asList(A, B, C, D));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void usesAnnotationPropertiesWhenPossible() throws Exception {
|
||||
MetadataReaderFactory readerFactory = mock(MetadataReaderFactory.class);
|
||||
this.autoConfigurationMetadata = getAutoConfigurationMetadata(A2, B, C, W2, X);
|
||||
this.sorter = new AutoConfigurationSorter(readerFactory,
|
||||
this.autoConfigurationMetadata);
|
||||
List<String> actual = this.sorter
|
||||
.getInPriorityOrder(Arrays.asList(A2, B, C, W2, X));
|
||||
assertThat(actual).containsExactly(C, W2, B, A2, X);
|
||||
}
|
||||
|
||||
private AutoConfigurationMetadata getAutoConfigurationMetadata(String... classNames)
|
||||
throws Exception {
|
||||
Properties properties = new Properties();
|
||||
for (String className : classNames) {
|
||||
Class<?> type = ClassUtils.forName(className, null);
|
||||
properties.put(type.getName(), "");
|
||||
AutoConfigureOrder order = type
|
||||
.getDeclaredAnnotation(AutoConfigureOrder.class);
|
||||
if (order != null) {
|
||||
properties.put(className + ".AutoConfigureOrder",
|
||||
String.valueOf(order.value()));
|
||||
}
|
||||
AutoConfigureBefore autoConfigureBefore = type
|
||||
.getDeclaredAnnotation(AutoConfigureBefore.class);
|
||||
if (autoConfigureBefore != null) {
|
||||
properties.put(className + ".AutoConfigureBefore",
|
||||
merge(autoConfigureBefore.value(), autoConfigureBefore.name()));
|
||||
}
|
||||
AutoConfigureAfter autoConfigureAfter = type
|
||||
.getDeclaredAnnotation(AutoConfigureAfter.class);
|
||||
if (autoConfigureAfter != null) {
|
||||
properties.put(className + ".AutoConfigureAfter",
|
||||
merge(autoConfigureAfter.value(), autoConfigureAfter.name()));
|
||||
}
|
||||
}
|
||||
return AutoConfigurationMetadataLoader.loadMetadata(properties);
|
||||
}
|
||||
|
||||
private String merge(Class<?>[] value, String[] name) {
|
||||
Set<String> items = new LinkedHashSet<String>();
|
||||
for (Class<?> type : value) {
|
||||
items.add(type.getName());
|
||||
}
|
||||
for (String type : name) {
|
||||
items.add(type);
|
||||
}
|
||||
return StringUtils.collectionToCommaDelimitedString(items);
|
||||
}
|
||||
|
||||
@AutoConfigureOrder(Ordered.LOWEST_PRECEDENCE)
|
||||
public static class OrderLowest {
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2012-2016 the original author or authors.
|
||||
* Copyright 2012-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
|
@ -16,6 +16,8 @@
|
|||
|
||||
package org.springframework.boot.autoconfigure;
|
||||
|
||||
import java.util.Properties;
|
||||
|
||||
import org.springframework.core.type.classreading.MetadataReaderFactory;
|
||||
|
||||
/**
|
||||
|
|
@ -26,7 +28,8 @@ import org.springframework.core.type.classreading.MetadataReaderFactory;
|
|||
public class TestAutoConfigurationSorter extends AutoConfigurationSorter {
|
||||
|
||||
public TestAutoConfigurationSorter(MetadataReaderFactory metadataReaderFactory) {
|
||||
super(metadataReaderFactory);
|
||||
super(metadataReaderFactory,
|
||||
AutoConfigurationMetadataLoader.loadMetadata(new Properties()));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue