Skip to content

Commit fa6a138

Browse files
committed
Refine ImportsContextCustomizer cache logic
Update `ImportsContextCustomizer` so that whenever possible a more specific cache key is used. Prior to this commit the customizer would generate a key based on *all* annotations on the test class. This has repeatedly caused issues where test classes that should have the same cache key did not due to unrelated annotations. A new `DeterminableImports` interface has been added that can be implemented by `ImportSelector` and `ImportBeanDefinitionRegistrar` implementations that are able to determine their imports early. The existing `ImportAutoConfigurationImportSelector` and `AutoConfigurationPackages` classes have been retrofitted with this interface. Fixes spring-projectsgh-7953
1 parent aaf118c commit fa6a138

File tree

8 files changed

+638
-38
lines changed

8 files changed

+638
-38
lines changed

spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/AutoConfigurationPackages.java

Lines changed: 45 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2012-2016 the original author or authors.
2+
* Copyright 2012-2017 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -18,6 +18,7 @@
1818

1919
import java.util.ArrayList;
2020
import java.util.Arrays;
21+
import java.util.Collections;
2122
import java.util.LinkedHashSet;
2223
import java.util.List;
2324
import java.util.Set;
@@ -31,6 +32,7 @@
3132
import org.springframework.beans.factory.config.ConstructorArgumentValues;
3233
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
3334
import org.springframework.beans.factory.support.GenericBeanDefinition;
35+
import org.springframework.boot.context.annotation.DeterminableImports;
3436
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
3537
import org.springframework.core.Ordered;
3638
import org.springframework.core.annotation.Order;
@@ -122,12 +124,52 @@ private static String[] addBasePackages(
122124
* configuration.
123125
*/
124126
@Order(Ordered.HIGHEST_PRECEDENCE)
125-
static class Registrar implements ImportBeanDefinitionRegistrar {
127+
static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports {
126128

127129
@Override
128130
public void registerBeanDefinitions(AnnotationMetadata metadata,
129131
BeanDefinitionRegistry registry) {
130-
register(registry, ClassUtils.getPackageName(metadata.getClassName()));
132+
register(registry, new PackageImport(metadata).getPackageName());
133+
}
134+
135+
@Override
136+
public Set<Object> determineImports(AnnotationMetadata metadata) {
137+
return Collections.<Object>singleton(new PackageImport(metadata));
138+
}
139+
140+
}
141+
142+
/**
143+
* Wrapper for a package import.
144+
*/
145+
private final static class PackageImport {
146+
147+
private final String packageName;
148+
149+
PackageImport(AnnotationMetadata metadata) {
150+
this.packageName = ClassUtils.getPackageName(metadata.getClassName());
151+
}
152+
153+
@Override
154+
public int hashCode() {
155+
return this.packageName.hashCode();
156+
}
157+
158+
@Override
159+
public boolean equals(Object obj) {
160+
if (obj == null || getClass() != obj.getClass()) {
161+
return false;
162+
}
163+
return this.packageName.equals(((PackageImport) obj).packageName);
164+
}
165+
166+
public String getPackageName() {
167+
return this.packageName;
168+
}
169+
170+
@Override
171+
public String toString() {
172+
return "Package Import " + this.packageName;
131173
}
132174

133175
}

spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/ImportAutoConfigurationImportSelector.java

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
import java.util.Map;
2828
import java.util.Set;
2929

30+
import org.springframework.boot.context.annotation.DeterminableImports;
3031
import org.springframework.core.annotation.AnnotatedElementUtils;
3132
import org.springframework.core.annotation.AnnotationAttributes;
3233
import org.springframework.core.annotation.AnnotationUtils;
@@ -44,7 +45,8 @@
4445
* @author Phillip Webb
4546
* @author Andy Wilkinson
4647
*/
47-
class ImportAutoConfigurationImportSelector extends AutoConfigurationImportSelector {
48+
class ImportAutoConfigurationImportSelector extends AutoConfigurationImportSelector
49+
implements DeterminableImports {
4850

4951
private static final Set<String> ANNOTATION_NAMES;
5052

@@ -55,6 +57,14 @@ class ImportAutoConfigurationImportSelector extends AutoConfigurationImportSelec
5557
ANNOTATION_NAMES = Collections.unmodifiableSet(names);
5658
}
5759

60+
@Override
61+
public Set<Object> determineImports(AnnotationMetadata metadata) {
62+
Set<String> result = new LinkedHashSet<String>();
63+
result.addAll(getCandidateConfigurations(metadata, null));
64+
result.removeAll(getExclusions(metadata, null));
65+
return Collections.<Object>unmodifiableSet(result);
66+
}
67+
5868
@Override
5969
protected AnnotationAttributes getAttributes(AnnotationMetadata metadata) {
6070
return null;
@@ -85,6 +95,10 @@ private Collection<String> getConfigurationsForAnnotation(Class<?> source,
8595
if (classes.length > 0) {
8696
return Arrays.asList(classes);
8797
}
98+
return loadFactoryNames(source);
99+
}
100+
101+
protected Collection<String> loadFactoryNames(Class<?> source) {
88102
return SpringFactoriesLoader.loadFactoryNames(source,
89103
getClass().getClassLoader());
90104
}
@@ -117,7 +131,8 @@ protected Set<String> getExclusions(AnnotationMetadata metadata,
117131
return exclusions;
118132
}
119133

120-
private Map<Class<?>, List<Annotation>> getAnnotations(AnnotationMetadata metadata) {
134+
protected final Map<Class<?>, List<Annotation>> getAnnotations(
135+
AnnotationMetadata metadata) {
121136
MultiValueMap<Class<?>, Annotation> annotations = new LinkedMultiValueMap<Class<?>, Annotation>();
122137
Class<?> source = ClassUtils.resolveClassName(metadata.getClassName(), null);
123138
collectAnnotations(source, annotations, new HashSet<Class<?>>());

0 commit comments

Comments
 (0)