From 1cb6e3dbb6e5a5f15ec06f4abc297821606ab2a6 Mon Sep 17 00:00:00 2001 From: Juergen Hoeller Date: Wed, 12 Dec 2012 03:07:29 +0100 Subject: [PATCH] Several enhancements with respect to CachingMetadataReaderFactory handling. Added "clearCache()" method to CachingMetadataReaderFactory, for clearing the metadata cache once not needed anymore - in particular when the MetadataReaderFactory instance is long-lived. Also added "setMetadataReaderFactory" method to ClassPathScanningCandidateComponentProvider, analogous to ConfigurationClassPostProcessor. --- .../AnnotationConfigApplicationContext.java | 6 +++ ...athScanningCandidateComponentProvider.java | 48 +++++++++++++++---- .../ConfigurationClassPostProcessor.java | 4 ++ .../CachingMetadataReaderFactory.java | 19 ++++++-- 4 files changed, 63 insertions(+), 14 deletions(-) diff --git a/spring-context/src/main/java/org/springframework/context/annotation/AnnotationConfigApplicationContext.java b/spring-context/src/main/java/org/springframework/context/annotation/AnnotationConfigApplicationContext.java index d147a50656..4576ab3bba 100644 --- a/spring-context/src/main/java/org/springframework/context/annotation/AnnotationConfigApplicationContext.java +++ b/spring-context/src/main/java/org/springframework/context/annotation/AnnotationConfigApplicationContext.java @@ -153,4 +153,10 @@ public class AnnotationConfigApplicationContext extends GenericApplicationContex this.scanner.scan(basePackages); } + @Override + protected void prepareRefresh() { + this.scanner.clearCache(); + super.prepareRefresh(); + } + } diff --git a/spring-context/src/main/java/org/springframework/context/annotation/ClassPathScanningCandidateComponentProvider.java b/spring-context/src/main/java/org/springframework/context/annotation/ClassPathScanningCandidateComponentProvider.java index 2afeba197e..6dacb49d60 100644 --- a/spring-context/src/main/java/org/springframework/context/annotation/ClassPathScanningCandidateComponentProvider.java +++ b/spring-context/src/main/java/org/springframework/context/annotation/ClassPathScanningCandidateComponentProvider.java @@ -25,6 +25,7 @@ import java.util.Set; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; + import org.springframework.beans.factory.BeanDefinitionStoreException; import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition; import org.springframework.beans.factory.config.BeanDefinition; @@ -78,7 +79,8 @@ public class ClassPathScanningCandidateComponentProvider implements EnvironmentC private ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver(); - private MetadataReaderFactory metadataReaderFactory = new CachingMetadataReaderFactory(this.resourcePatternResolver); + private MetadataReaderFactory metadataReaderFactory = + new CachingMetadataReaderFactory(this.resourcePatternResolver); private String resourcePattern = DEFAULT_RESOURCE_PATTERN; @@ -120,6 +122,31 @@ public class ClassPathScanningCandidateComponentProvider implements EnvironmentC this.metadataReaderFactory = new CachingMetadataReaderFactory(resourceLoader); } + /** + * Return the ResourceLoader that this component provider uses. + */ + public final ResourceLoader getResourceLoader() { + return this.resourcePatternResolver; + } + + /** + * Set the {@link MetadataReaderFactory} to use. + *

Default is a {@link CachingMetadataReaderFactory} for the specified + * {@linkplain #setResourceLoader resource loader}. + *

Call this setter method after {@link #setResourceLoader} in order + * for the given MetadataReaderFactory to override the default factory. + */ + public void setMetadataReaderFactory(MetadataReaderFactory metadataReaderFactory) { + this.metadataReaderFactory = metadataReaderFactory; + } + + /** + * Return the MetadataReaderFactory used by this component provider. + */ + public final MetadataReaderFactory getMetadataReaderFactory() { + return this.metadataReaderFactory; + } + /** * Set the Environment to use when resolving placeholders and evaluating * {@link Profile @Profile}-annotated component classes. @@ -130,17 +157,10 @@ public class ClassPathScanningCandidateComponentProvider implements EnvironmentC this.environment = environment; } - public Environment getEnvironment() { + public final Environment getEnvironment() { return this.environment; } - /** - * Return the ResourceLoader that this component provider uses. - */ - public final ResourceLoader getResourceLoader() { - return this.resourcePatternResolver; - } - /** * Set the resource pattern to use when scanning the classpath. * This value will be appended to each base package name. @@ -324,4 +344,14 @@ public class ClassPathScanningCandidateComponentProvider implements EnvironmentC return (beanDefinition.getMetadata().isConcrete() && beanDefinition.getMetadata().isIndependent()); } + + /** + * Clear the underlying metadata cache, removing all cached class metadata. + */ + public void clearCache() { + if (this.metadataReaderFactory instanceof CachingMetadataReaderFactory) { + ((CachingMetadataReaderFactory) this.metadataReaderFactory).clearCache(); + } + } + } diff --git a/spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClassPostProcessor.java b/spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClassPostProcessor.java index 45e937e722..f2fa6273e6 100644 --- a/spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClassPostProcessor.java +++ b/spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClassPostProcessor.java @@ -320,6 +320,10 @@ public class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPo singletonRegistry.registerSingleton(IMPORT_REGISTRY_BEAN_NAME, parser.getImportRegistry()); } } + + if (this.metadataReaderFactory instanceof CachingMetadataReaderFactory) { + ((CachingMetadataReaderFactory) this.metadataReaderFactory).clearCache(); + } } /** diff --git a/spring-core/src/main/java/org/springframework/core/type/classreading/CachingMetadataReaderFactory.java b/spring-core/src/main/java/org/springframework/core/type/classreading/CachingMetadataReaderFactory.java index 725b70f964..5f9bd68ee6 100644 --- a/spring-core/src/main/java/org/springframework/core/type/classreading/CachingMetadataReaderFactory.java +++ b/spring-core/src/main/java/org/springframework/core/type/classreading/CachingMetadataReaderFactory.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2010 the original author or authors. + * Copyright 2002-2012 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. @@ -40,7 +40,7 @@ public class CachingMetadataReaderFactory extends SimpleMetadataReaderFactory { private volatile int cacheLimit = DEFAULT_CACHE_LIMIT; - private final Map classReaderCache = + private final Map metadataReaderCache = new LinkedHashMap(DEFAULT_CACHE_LIMIT, 0.75f, true) { @Override protected boolean removeEldestEntry(Map.Entry eldest) { @@ -95,14 +95,23 @@ public class CachingMetadataReaderFactory extends SimpleMetadataReaderFactory { if (getCacheLimit() <= 0) { return super.getMetadataReader(resource); } - synchronized (this.classReaderCache) { - MetadataReader metadataReader = this.classReaderCache.get(resource); + synchronized (this.metadataReaderCache) { + MetadataReader metadataReader = this.metadataReaderCache.get(resource); if (metadataReader == null) { metadataReader = super.getMetadataReader(resource); - this.classReaderCache.put(resource, metadataReader); + this.metadataReaderCache.put(resource, metadataReader); } return metadataReader; } } + /** + * Clear the entire MetadataReader cache, removing all cached class metadata. + */ + public void clearCache() { + synchronized (this.metadataReaderCache) { + this.metadataReaderCache.clear(); + } + } + }