diff --git a/spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClassParser.java b/spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClassParser.java index 26fcec4b93..153ff14684 100644 --- a/spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClassParser.java +++ b/spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClassParser.java @@ -23,6 +23,7 @@ import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; +import java.util.HashSet; import java.util.Iterator; import java.util.LinkedHashSet; import java.util.Map; @@ -100,6 +101,8 @@ class ConfigurationClassParser { private final ImportStack importStack = new ImportStack(); + private final Set> importBeanDefinitionRegistrars = new HashSet>(); + /** * Create a new {@link ConfigurationClassParser} instance that will be used @@ -370,25 +373,32 @@ class ConfigurationClassParser { Object candidateToCheck = (candidate instanceof Class ? (Class) candidate : this.metadataReaderFactory.getMetadataReader((String) candidate)); if (checkAssignability(ImportSelector.class, candidateToCheck)) { - // the candidate class is an ImportSelector -> delegate to it to determine imports + // Candidate class is an ImportSelector -> delegate to it to determine imports Class candidateClass = (candidate instanceof Class ? (Class) candidate : this.resourceLoader.getClassLoader().loadClass((String) candidate)); ImportSelector selector = BeanUtils.instantiateClass(candidateClass, ImportSelector.class); processImport(configClass, metadata, Arrays.asList(selector.selectImports(metadata)), false); } else if (checkAssignability(ImportBeanDefinitionRegistrar.class, candidateToCheck)) { - // the candidate class is an ImportBeanDefinitionRegistrar -> delegate to it to register additional bean definitions + // Candidate class is an ImportBeanDefinitionRegistrar -> + // delegate to it to register additional bean definitions Class candidateClass = (candidate instanceof Class ? (Class) candidate : this.resourceLoader.getClassLoader().loadClass((String) candidate)); - ImportBeanDefinitionRegistrar registrar = BeanUtils.instantiateClass(candidateClass, ImportBeanDefinitionRegistrar.class); - invokeAwareMethods(registrar); - registrar.registerBeanDefinitions(metadata, this.registry); + if (!this.importBeanDefinitionRegistrars.contains(candidateClass)) { + ImportBeanDefinitionRegistrar registrar = + BeanUtils.instantiateClass(candidateClass, ImportBeanDefinitionRegistrar.class); + invokeAwareMethods(registrar); + registrar.registerBeanDefinitions(metadata, this.registry); + this.importBeanDefinitionRegistrars.add(candidateClass); + } } else { - // candidate class not an ImportSelector or ImportBeanDefinitionRegistrar -> process it as a @Configuration class + // Candidate class not an ImportSelector or ImportBeanDefinitionRegistrar -> + // process it as a @Configuration class this.importStack.registerImport(metadata, (candidate instanceof Class ? ((Class) candidate).getName() : (String) candidate)); - processConfigurationClass(candidateToCheck instanceof Class ? new ConfigurationClass((Class) candidateToCheck, true) : + processConfigurationClass(candidateToCheck instanceof Class ? + new ConfigurationClass((Class) candidateToCheck, true) : new ConfigurationClass((MetadataReader) candidateToCheck, true)); } } diff --git a/spring-context/src/test/java/org/springframework/context/annotation/spr12334/Spr12334Tests.java b/spring-context/src/test/java/org/springframework/context/annotation/spr12334/Spr12334Tests.java new file mode 100644 index 0000000000..c98fc07738 --- /dev/null +++ b/spring-context/src/test/java/org/springframework/context/annotation/spr12334/Spr12334Tests.java @@ -0,0 +1,69 @@ +/* + * Copyright 2002-2014 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.context.annotation.spr12334; + +import org.junit.Test; + +import org.springframework.beans.factory.support.BeanDefinitionRegistry; +import org.springframework.context.annotation.AnnotationConfigApplicationContext; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Import; +import org.springframework.context.annotation.ImportBeanDefinitionRegistrar; +import org.springframework.core.type.AnnotationMetadata; + +/** + * @author Juergen Hoeller + * @author Alex Pogrebnyak + */ +public class Spr12334Tests { + + @Test + public void shouldNotScanTwice() { + TestImport.scanned = false; + + AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); + context.scan(TestImport.class.getPackage().getName()); + context.refresh(); + context.getBean(TestConfiguration.class); + } + + + @Import(TestImport.class) + public @interface AnotherImport { + } + + + @Configuration + @AnotherImport + public static class TestConfiguration { + } + + + public static class TestImport implements ImportBeanDefinitionRegistrar { + + private static boolean scanned = false; + + @Override + public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) { + if (scanned) { + throw new IllegalStateException("Already scanned"); + } + scanned = true; + } + } + +}