Skip to content

Commit 7818c65

Browse files
committed
Cache ASM metadata at the context level (if supported)
Includes streamlined ClassPathBeanDefinitionScanner setup. Issue: SPR-14654
1 parent 0480981 commit 7818c65

File tree

10 files changed

+256
-147
lines changed

10 files changed

+256
-147
lines changed

spring-context/src/main/java/org/springframework/context/annotation/AnnotationConfigApplicationContext.java

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -38,10 +38,10 @@
3838
* deliberately override certain bean definitions via an extra {@code @Configuration}
3939
* class.
4040
*
41-
* <p>See @{@link Configuration} Javadoc for usage examples.
41+
* <p>See @{@link Configuration}'s javadoc for usage examples.
4242
*
43-
* @author Chris Beams
4443
* @author Juergen Hoeller
44+
* @author Chris Beams
4545
* @since 3.0
4646
* @see #register
4747
* @see #scan
@@ -138,12 +138,6 @@ public void setScopeMetadataResolver(ScopeMetadataResolver scopeMetadataResolver
138138
this.scanner.setScopeMetadataResolver(scopeMetadataResolver);
139139
}
140140

141-
@Override
142-
protected void prepareRefresh() {
143-
this.scanner.clearCache();
144-
super.prepareRefresh();
145-
}
146-
147141

148142
//---------------------------------------------------------------------
149143
// Implementation of AnnotationConfigRegistry

spring-context/src/main/java/org/springframework/context/annotation/ClassPathBeanDefinitionScanner.java

Lines changed: 32 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -132,16 +132,39 @@ public ClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry, boolean u
132132
* @since 3.1
133133
* @see #setResourceLoader
134134
*/
135-
public ClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry, boolean useDefaultFilters, Environment environment) {
136-
super(useDefaultFilters, environment);
135+
public ClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry, boolean useDefaultFilters,
136+
Environment environment) {
137+
138+
this(registry, useDefaultFilters, environment,
139+
(registry instanceof ResourceLoader ? (ResourceLoader) registry : null));
140+
}
141+
142+
/**
143+
* Create a new {@code ClassPathBeanDefinitionScanner} for the given bean factory and
144+
* using the given {@link Environment} when evaluating bean definition profile metadata.
145+
* @param registry the {@code BeanFactory} to load bean definitions into, in the form
146+
* of a {@code BeanDefinitionRegistry}
147+
* @param useDefaultFilters whether to include the default filters for the
148+
* {@link org.springframework.stereotype.Component @Component},
149+
* {@link org.springframework.stereotype.Repository @Repository},
150+
* {@link org.springframework.stereotype.Service @Service}, and
151+
* {@link org.springframework.stereotype.Controller @Controller} stereotype annotations
152+
* @param environment the Spring {@link Environment} to use when evaluating bean
153+
* definition profile metadata
154+
* @param resourceLoader the {@link ResourceLoader} to use
155+
* @since 4.3.6
156+
*/
157+
public ClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry, boolean useDefaultFilters,
158+
Environment environment, ResourceLoader resourceLoader) {
137159

138160
Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
139161
this.registry = registry;
140162

141-
// Determine ResourceLoader to use.
142-
if (this.registry instanceof ResourceLoader) {
143-
setResourceLoader((ResourceLoader) this.registry);
163+
if (useDefaultFilters) {
164+
registerDefaultFilters();
144165
}
166+
setEnvironment(environment);
167+
setResourceLoader(resourceLoader);
145168
}
146169

147170

@@ -192,7 +215,8 @@ public void setBeanNameGenerator(BeanNameGenerator beanNameGenerator) {
192215
* @see #setScopedProxyMode
193216
*/
194217
public void setScopeMetadataResolver(ScopeMetadataResolver scopeMetadataResolver) {
195-
this.scopeMetadataResolver = (scopeMetadataResolver != null ? scopeMetadataResolver : new AnnotationScopeMetadataResolver());
218+
this.scopeMetadataResolver =
219+
(scopeMetadataResolver != null ? scopeMetadataResolver : new AnnotationScopeMetadataResolver());
196220
}
197221

198222
/**
@@ -258,7 +282,8 @@ protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
258282
}
259283
if (checkCandidate(beanName, candidate)) {
260284
BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
261-
definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
285+
definitionHolder =
286+
AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
262287
beanDefinitions.add(definitionHolder);
263288
registerBeanDefinition(definitionHolder, this.registry);
264289
}

spring-context/src/main/java/org/springframework/context/annotation/ClassPathScanningCandidateComponentProvider.java

Lines changed: 86 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,6 @@
4141
import org.springframework.core.env.StandardEnvironment;
4242
import org.springframework.core.io.Resource;
4343
import org.springframework.core.io.ResourceLoader;
44-
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
4544
import org.springframework.core.io.support.ResourcePatternResolver;
4645
import org.springframework.core.io.support.ResourcePatternUtils;
4746
import org.springframework.core.type.classreading.CachingMetadataReaderFactory;
@@ -63,7 +62,7 @@
6362
* use {@link CandidateComponentsIndex the index} if it is available of scans the
6463
* classpath otherwise. Candidate components are identified by applying exclude and
6564
* include filters. {@link AnnotationTypeFilter}, {@link AssignableTypeFilter} include
66-
* filters on an annotation/super-class that are annotated with {@link Indexed} are
65+
* filters on an annotation/superclass that are annotated with {@link Indexed} are
6766
* supported: if any other include filter is specified, the index is ignored and
6867
* classpath scanning is used instead.
6968
*
@@ -86,25 +85,32 @@ public class ClassPathScanningCandidateComponentProvider implements EnvironmentC
8685

8786
static final String DEFAULT_RESOURCE_PATTERN = "**/*.class";
8887

89-
protected final Log logger = LogFactory.getLog(getClass());
90-
91-
private Environment environment;
92-
93-
private ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver();
94-
95-
private MetadataReaderFactory metadataReaderFactory =
96-
new CachingMetadataReaderFactory(this.resourcePatternResolver);
9788

98-
private CandidateComponentsIndex componentsIndex;
89+
protected final Log logger = LogFactory.getLog(getClass());
9990

10091
private String resourcePattern = DEFAULT_RESOURCE_PATTERN;
10192

10293
private final List<TypeFilter> includeFilters = new LinkedList<>();
10394

10495
private final List<TypeFilter> excludeFilters = new LinkedList<>();
10596

97+
private Environment environment;
98+
10699
private ConditionEvaluator conditionEvaluator;
107100

101+
private ResourcePatternResolver resourcePatternResolver;
102+
103+
private MetadataReaderFactory metadataReaderFactory;
104+
105+
private CandidateComponentsIndex componentsIndex;
106+
107+
108+
/**
109+
* Protected constructor for flexible subclass initialization.
110+
* @since 4.3.6
111+
*/
112+
protected ClassPathScanningCandidateComponentProvider() {
113+
}
108114

109115
/**
110116
* Create a ClassPathScanningCandidateComponentProvider with a {@link StandardEnvironment}.
@@ -131,74 +137,10 @@ public ClassPathScanningCandidateComponentProvider(boolean useDefaultFilters, En
131137
if (useDefaultFilters) {
132138
registerDefaultFilters();
133139
}
134-
Assert.notNull(environment, "Environment must not be null");
135-
this.environment = environment;
136-
}
137-
138-
139-
/**
140-
* Set the ResourceLoader to use for resource locations.
141-
* This will typically be a ResourcePatternResolver implementation.
142-
* <p>Default is PathMatchingResourcePatternResolver, also capable of
143-
* resource pattern resolving through the ResourcePatternResolver interface.
144-
* @see org.springframework.core.io.support.ResourcePatternResolver
145-
* @see org.springframework.core.io.support.PathMatchingResourcePatternResolver
146-
*/
147-
@Override
148-
public void setResourceLoader(ResourceLoader resourceLoader) {
149-
this.resourcePatternResolver = ResourcePatternUtils.getResourcePatternResolver(resourceLoader);
150-
this.metadataReaderFactory = new CachingMetadataReaderFactory(resourceLoader);
151-
this.componentsIndex = CandidateComponentsIndexLoader.loadIndex(resourceLoader.getClassLoader());
152-
}
153-
154-
/**
155-
* Return the ResourceLoader that this component provider uses.
156-
*/
157-
public final ResourceLoader getResourceLoader() {
158-
return this.resourcePatternResolver;
140+
setEnvironment(environment);
141+
setResourceLoader(null);
159142
}
160143

161-
/**
162-
* Set the {@link MetadataReaderFactory} to use.
163-
* <p>Default is a {@link CachingMetadataReaderFactory} for the specified
164-
* {@linkplain #setResourceLoader resource loader}.
165-
* <p>Call this setter method <i>after</i> {@link #setResourceLoader} in order
166-
* for the given MetadataReaderFactory to override the default factory.
167-
*/
168-
public void setMetadataReaderFactory(MetadataReaderFactory metadataReaderFactory) {
169-
this.metadataReaderFactory = metadataReaderFactory;
170-
}
171-
172-
/**
173-
* Return the MetadataReaderFactory used by this component provider.
174-
*/
175-
public final MetadataReaderFactory getMetadataReaderFactory() {
176-
return this.metadataReaderFactory;
177-
}
178-
179-
/**
180-
* Set the Environment to use when resolving placeholders and evaluating
181-
* {@link Conditional @Conditional}-annotated component classes.
182-
* <p>The default is a {@link StandardEnvironment}.
183-
* @param environment the Environment to use
184-
*/
185-
public void setEnvironment(Environment environment) {
186-
Assert.notNull(environment, "Environment must not be null");
187-
this.environment = environment;
188-
this.conditionEvaluator = null;
189-
}
190-
191-
@Override
192-
public final Environment getEnvironment() {
193-
return this.environment;
194-
}
195-
196-
/**
197-
* Returns the {@link BeanDefinitionRegistry} used by this scanner, if any.
198-
*/
199-
protected BeanDefinitionRegistry getRegistry() {
200-
return null;
201-
}
202144

203145
/**
204146
* Set the resource pattern to use when scanning the classpath.
@@ -273,6 +215,70 @@ protected void registerDefaultFilters() {
273215
}
274216
}
275217

218+
/**
219+
* Set the Environment to use when resolving placeholders and evaluating
220+
* {@link Conditional @Conditional}-annotated component classes.
221+
* <p>The default is a {@link StandardEnvironment}.
222+
* @param environment the Environment to use
223+
*/
224+
public void setEnvironment(Environment environment) {
225+
Assert.notNull(environment, "Environment must not be null");
226+
this.environment = environment;
227+
this.conditionEvaluator = null;
228+
}
229+
230+
@Override
231+
public final Environment getEnvironment() {
232+
return this.environment;
233+
}
234+
235+
/**
236+
* Return the {@link BeanDefinitionRegistry} used by this scanner, if any.
237+
*/
238+
protected BeanDefinitionRegistry getRegistry() {
239+
return null;
240+
}
241+
242+
/**
243+
* Set the {@link ResourceLoader} to use for resource locations.
244+
* This will typically be a {@link ResourcePatternResolver} implementation.
245+
* <p>Default is a {@code PathMatchingResourcePatternResolver}, also capable of
246+
* resource pattern resolving through the {@code ResourcePatternResolver} interface.
247+
* @see org.springframework.core.io.support.ResourcePatternResolver
248+
* @see org.springframework.core.io.support.PathMatchingResourcePatternResolver
249+
*/
250+
@Override
251+
public void setResourceLoader(ResourceLoader resourceLoader) {
252+
this.resourcePatternResolver = ResourcePatternUtils.getResourcePatternResolver(resourceLoader);
253+
this.metadataReaderFactory = new CachingMetadataReaderFactory(resourceLoader);
254+
this.componentsIndex = CandidateComponentsIndexLoader.loadIndex(this.resourcePatternResolver.getClassLoader());
255+
}
256+
257+
/**
258+
* Return the ResourceLoader that this component provider uses.
259+
*/
260+
public final ResourceLoader getResourceLoader() {
261+
return this.resourcePatternResolver;
262+
}
263+
264+
/**
265+
* Set the {@link MetadataReaderFactory} to use.
266+
* <p>Default is a {@link CachingMetadataReaderFactory} for the specified
267+
* {@linkplain #setResourceLoader resource loader}.
268+
* <p>Call this setter method <i>after</i> {@link #setResourceLoader} in order
269+
* for the given MetadataReaderFactory to override the default factory.
270+
*/
271+
public void setMetadataReaderFactory(MetadataReaderFactory metadataReaderFactory) {
272+
this.metadataReaderFactory = metadataReaderFactory;
273+
}
274+
275+
/**
276+
* Return the MetadataReaderFactory used by this component provider.
277+
*/
278+
public final MetadataReaderFactory getMetadataReaderFactory() {
279+
return this.metadataReaderFactory;
280+
}
281+
276282

277283
/**
278284
* Scan the class path for candidate components.
@@ -496,10 +502,12 @@ protected String extractStereotype(TypeFilter filter) {
496502
}
497503

498504
/**
499-
* Clear the underlying metadata cache, removing all cached class metadata.
505+
* Clear the local metadata cache, if any, removing all cached class metadata.
500506
*/
501507
public void clearCache() {
502508
if (this.metadataReaderFactory instanceof CachingMetadataReaderFactory) {
509+
// Clear cache in externally provided MetadataReaderFactory; this is a no-op
510+
// for a shared cache since it'll be cleared by the ApplicationContext.
503511
((CachingMetadataReaderFactory) this.metadataReaderFactory).clearCache();
504512
}
505513
}

spring-context/src/main/java/org/springframework/context/annotation/ComponentScanAnnotationParser.java

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -77,10 +77,8 @@ public Set<BeanDefinitionHolder> parse(AnnotationAttributes componentScan, final
7777
Assert.state(this.environment != null, "Environment must not be null");
7878
Assert.state(this.resourceLoader != null, "ResourceLoader must not be null");
7979

80-
ClassPathBeanDefinitionScanner scanner =
81-
new ClassPathBeanDefinitionScanner(this.registry, componentScan.getBoolean("useDefaultFilters"));
82-
scanner.setEnvironment(this.environment);
83-
scanner.setResourceLoader(this.resourceLoader);
80+
ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(this.registry,
81+
componentScan.getBoolean("useDefaultFilters"), this.environment, this.resourceLoader);
8482

8583
Class<? extends BeanNameGenerator> generatorClass = componentScan.getClass("nameGenerator");
8684
boolean useInheritedGenerator = (BeanNameGenerator.class == generatorClass);

spring-context/src/main/java/org/springframework/context/annotation/ComponentScanBeanDefinitionParser.java

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -99,8 +99,6 @@ protected ClassPathBeanDefinitionScanner configureScanner(ParserContext parserCo
9999

100100
// Delegate bean definition registration to scanner class.
101101
ClassPathBeanDefinitionScanner scanner = createScanner(parserContext.getReaderContext(), useDefaultFilters);
102-
scanner.setResourceLoader(parserContext.getReaderContext().getResourceLoader());
103-
scanner.setEnvironment(parserContext.getReaderContext().getEnvironment());
104102
scanner.setBeanDefinitionDefaults(parserContext.getDelegate().getBeanDefinitionDefaults());
105103
scanner.setAutowireCandidatePatterns(parserContext.getDelegate().getAutowireCandidatePatterns());
106104

@@ -128,7 +126,8 @@ protected ClassPathBeanDefinitionScanner configureScanner(ParserContext parserCo
128126
}
129127

130128
protected ClassPathBeanDefinitionScanner createScanner(XmlReaderContext readerContext, boolean useDefaultFilters) {
131-
return new ClassPathBeanDefinitionScanner(readerContext.getRegistry(), useDefaultFilters);
129+
return new ClassPathBeanDefinitionScanner(readerContext.getRegistry(), useDefaultFilters,
130+
readerContext.getEnvironment(), readerContext.getResourceLoader());
132131
}
133132

134133
protected void registerComponents(

spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClassPostProcessor.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -350,6 +350,8 @@ public int compare(BeanDefinitionHolder bd1, BeanDefinitionHolder bd2) {
350350
}
351351

352352
if (this.metadataReaderFactory instanceof CachingMetadataReaderFactory) {
353+
// Clear cache in externally provided MetadataReaderFactory; this is a no-op
354+
// for a shared cache since it'll be cleared by the ApplicationContext.
353355
((CachingMetadataReaderFactory) this.metadataReaderFactory).clearCache();
354356
}
355357
}

0 commit comments

Comments
 (0)