diff --git a/src/main/java/org/springframework/data/repository/config/RepositoryConfigurationExtensionSupport.java b/src/main/java/org/springframework/data/repository/config/RepositoryConfigurationExtensionSupport.java index 25b553a69..0e11b2883 100644 --- a/src/main/java/org/springframework/data/repository/config/RepositoryConfigurationExtensionSupport.java +++ b/src/main/java/org/springframework/data/repository/config/RepositoryConfigurationExtensionSupport.java @@ -118,7 +118,7 @@ public abstract class RepositoryConfigurationExtensionSupport implements Reposit AbstractBeanDefinition definition = BeanDefinitionBuilder.rootBeanDefinition(REPOSITORY_INTERFACE_POST_PROCESSOR) .getBeanDefinition(); - registerWithSourceAndGeneratedBeanName(registry, definition, configurationSource.getSource()); + registerIfNotAlreadyRegistered(definition, registry, REPOSITORY_INTERFACE_POST_PROCESSOR, configurationSource); } /** @@ -169,12 +169,15 @@ public abstract class RepositoryConfigurationExtensionSupport implements Reposit /** * Sets the given source on the given {@link AbstractBeanDefinition} and registers it inside the given - * {@link BeanDefinitionRegistry}. + * {@link BeanDefinitionRegistry}. For {@link BeanDefinition}s to be registerd once-and-only-once for all + * configuration elements (annotation or XML), prefer calling + * {@link #registerIfNotAlreadyRegistered(AbstractBeanDefinition, BeanDefinitionRegistry, String, Object)} with a + * dedicated bean name to avoid the bead definition being registered multiple times. * * - * @param registry - * @param bean - * @param source - * @return + * @param registry must not be {@literal null}. + * @param bean must not be {@literal null}. + * @param source must not be {@literal null}. + * @return the bean name generated for the given {@link BeanDefinition} */ public static String registerWithSourceAndGeneratedBeanName(BeanDefinitionRegistry registry, AbstractBeanDefinition bean, Object source) { @@ -187,6 +190,26 @@ public abstract class RepositoryConfigurationExtensionSupport implements Reposit return beanName; } + /** + * Registers the given {@link AbstractBeanDefinition} with the given registry with the given bean name unless the + * registry already contains a bean with that name. + * + * @param bean must not be {@literal null}. + * @param registry must not be {@literal null}. + * @param beanName must not be {@literal null} or empty. + * @param source must not be {@literal null}. + */ + public static void registerIfNotAlreadyRegistered(AbstractBeanDefinition bean, BeanDefinitionRegistry registry, + String beanName, Object source) { + + if (registry.containsBeanDefinition(beanName)) { + return; + } + + bean.setSource(source); + registry.registerBeanDefinition(beanName, bean); + } + /** * Returns whether the given {@link BeanDefinitionRegistry} already contains a bean of the given type assuming the * bean name has been autogenerated. diff --git a/src/test/java/org/springframework/data/repository/config/RepositoryConfigurationExtensionSupportUnitTests.java b/src/test/java/org/springframework/data/repository/config/RepositoryConfigurationExtensionSupportUnitTests.java index 468fe8d57..5bee74d04 100644 --- a/src/test/java/org/springframework/data/repository/config/RepositoryConfigurationExtensionSupportUnitTests.java +++ b/src/test/java/org/springframework/data/repository/config/RepositoryConfigurationExtensionSupportUnitTests.java @@ -23,7 +23,12 @@ import java.util.Collection; import java.util.Collections; import org.junit.Test; +import org.springframework.beans.factory.support.DefaultListableBeanFactory; import org.springframework.context.annotation.Primary; +import org.springframework.core.env.StandardEnvironment; +import org.springframework.core.io.DefaultResourceLoader; +import org.springframework.core.type.AnnotationMetadata; +import org.springframework.core.type.StandardAnnotationMetadata; import org.springframework.data.repository.Repository; import org.springframework.data.repository.core.support.RepositoryFactorySupport; @@ -60,6 +65,26 @@ public class RepositoryConfigurationExtensionSupportUnitTests { assertThat(extension.isStrictRepositoryCandidate(ExtendingInterface.class), is(true)); } + /** + * @see DATACMNS-609 + */ + @Test + public void registersRepositoryInterfaceAwareBeanPostProcessorOnlyOnceForMultipleConfigurations() { + + DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory(); + AnnotationMetadata annotationMetadata = new StandardAnnotationMetadata(SampleConfiguration.class, true); + + DefaultResourceLoader resourceLoader = new DefaultResourceLoader(); + StandardEnvironment environment = new StandardEnvironment(); + AnnotationRepositoryConfigurationSource configurationSource = new AnnotationRepositoryConfigurationSource( + annotationMetadata, EnableRepositories.class, resourceLoader, environment); + + extension.registerBeansForRoot(beanFactory, configurationSource); + extension.registerBeansForRoot(beanFactory, configurationSource); + + assertThat(beanFactory.getBeanDefinitionCount(), is(1)); + } + static class SampleRepositoryConfigurationExtension extends RepositoryConfigurationExtensionSupport { @Override @@ -95,4 +120,7 @@ public class RepositoryConfigurationExtensionSupportUnitTests { interface StoreInterface {} interface ExtendingInterface extends StoreInterface, Repository {} + + @EnableRepositories + static class SampleConfiguration {} }