diff --git a/src/main/java/org/springframework/data/repository/config/RepositoryConfigurationDelegate.java b/src/main/java/org/springframework/data/repository/config/RepositoryConfigurationDelegate.java index a8577ad75..6684411b6 100644 --- a/src/main/java/org/springframework/data/repository/config/RepositoryConfigurationDelegate.java +++ b/src/main/java/org/springframework/data/repository/config/RepositoryConfigurationDelegate.java @@ -15,28 +15,13 @@ */ package org.springframework.data.repository.config; -import java.lang.reflect.TypeVariable; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; - import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; - import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.beans.factory.config.ConfigurableBeanFactory; import org.springframework.beans.factory.config.DependencyDescriptor; import org.springframework.beans.factory.parsing.BeanComponentDefinition; -import org.springframework.beans.factory.support.AutowireCandidateResolver; -import org.springframework.beans.factory.support.BeanDefinitionBuilder; -import org.springframework.beans.factory.support.BeanDefinitionReaderUtils; -import org.springframework.beans.factory.support.BeanDefinitionRegistry; -import org.springframework.beans.factory.support.DefaultListableBeanFactory; -import org.springframework.beans.factory.support.RootBeanDefinition; +import org.springframework.beans.factory.support.*; import org.springframework.context.annotation.ContextAnnotationAutowireCandidateResolver; import org.springframework.context.support.GenericApplicationContext; import org.springframework.core.ResolvableType; @@ -57,6 +42,10 @@ import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.StopWatch; +import java.lang.reflect.TypeVariable; +import java.util.*; +import java.util.stream.Collectors; + /** * Delegate for configuration integration to reuse the general way of detecting repositories. Customization is done by * providing a configuration format specific {@link RepositoryConfigurationSource} (currently either XML or annotations @@ -92,7 +81,7 @@ public class RepositoryConfigurationDelegate { * @param environment must not be {@literal null}. */ public RepositoryConfigurationDelegate(RepositoryConfigurationSource configurationSource, - ResourceLoader resourceLoader, Environment environment) { + ResourceLoader resourceLoader, Environment environment) { this.isXml = configurationSource instanceof XmlRepositoryConfigurationSource; boolean isAnnotation = configurationSource instanceof AnnotationRepositoryConfigurationSource; @@ -117,7 +106,7 @@ public class RepositoryConfigurationDelegate { * {@link Environment}. */ private static Environment defaultEnvironment(@Nullable Environment environment, - @Nullable ResourceLoader resourceLoader) { + @Nullable ResourceLoader resourceLoader) { if (environment != null) { return environment; @@ -136,7 +125,7 @@ public class RepositoryConfigurationDelegate { * @see org.springframework.beans.factory.support.BeanDefinitionRegistry */ public List registerRepositoriesIn(BeanDefinitionRegistry registry, - RepositoryConfigurationExtension extension) { + RepositoryConfigurationExtension extension) { if (logger.isInfoEnabled()) { logger.info(LogMessage.format("Bootstrapping Spring Data %s repositories in %s mode.", // @@ -222,7 +211,7 @@ public class RepositoryConfigurationDelegate { } private void registerAotComponents(BeanDefinitionRegistry registry, RepositoryConfigurationExtension extension, - Map> metadataByRepositoryBeanName) { + Map> metadataByRepositoryBeanName) { BeanDefinitionBuilder repositoryAotProcessor = BeanDefinitionBuilder .rootBeanDefinition(extension.getRepositoryAotProcessor()).setRole(BeanDefinition.ROLE_INFRASTRUCTURE); @@ -245,7 +234,7 @@ public class RepositoryConfigurationDelegate { * @param registry must not be {@literal null}. */ private static void potentiallyLazifyRepositories(Map> configurations, - BeanDefinitionRegistry registry, BootstrapMode mode) { + BeanDefinitionRegistry registry, BootstrapMode mode) { if (!DefaultListableBeanFactory.class.isInstance(registry) || BootstrapMode.DEFAULT.equals(mode)) { return; @@ -272,8 +261,10 @@ public class RepositoryConfigurationDelegate { logger.debug("Registering deferred repository initialization listener."); - beanFactory.registerSingleton(DeferredRepositoryInitializationListener.class.getName(), - new DeferredRepositoryInitializationListener(beanFactory)); + if (!beanFactory.containsBean(DeferredRepositoryInitializationListener.class.getName())) { + beanFactory.registerSingleton(DeferredRepositoryInitializationListener.class.getName(), + new DeferredRepositoryInitializationListener(beanFactory)); + } } } diff --git a/src/test/java/org/springframework/data/repository/config/RepositoryConfigurationDelegateUnitTests.java b/src/test/java/org/springframework/data/repository/config/RepositoryConfigurationDelegateUnitTests.java index 340e36bcc..8ad1c906c 100644 --- a/src/test/java/org/springframework/data/repository/config/RepositoryConfigurationDelegateUnitTests.java +++ b/src/test/java/org/springframework/data/repository/config/RepositoryConfigurationDelegateUnitTests.java @@ -15,13 +15,6 @@ */ package org.springframework.data.repository.config; -import static org.assertj.core.api.Assertions.*; - -import java.lang.reflect.TypeVariable; -import java.util.List; -import java.util.Optional; -import java.util.UUID; - import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mockito; @@ -59,11 +52,19 @@ import org.springframework.data.repository.sample.AddressRepository; import org.springframework.data.repository.sample.AddressRepositoryClient; import org.springframework.data.repository.sample.ProductRepository; +import java.lang.reflect.TypeVariable; +import java.util.List; +import java.util.Optional; +import java.util.UUID; + +import static org.assertj.core.api.Assertions.assertThat; + /** * Unit tests for {@link RepositoryConfigurationDelegate}. * * @author Oliver Gierke * @author Mark Paluch + * @author xeounxzxu * @soundtrack Richard Spaven - Tribute (Whole Other*) */ @ExtendWith(MockitoExtension.class) @@ -109,7 +110,16 @@ class RepositoryConfigurationDelegateUnitTests { var beanFactory = assertLazyRepositoryBeanSetup(DeferredConfig.class); assertThat(beanFactory.getBeanNamesForType(DeferredRepositoryInitializationListener.class)).isNotEmpty(); + } + @Test + void registersMultiDeferredRepositoryInitializationListener() { + + var beanFactory = assertLazyRepositoryBeanSetup(DeferredConfig.class, OtherDeferredConfig.class); + + assertThat(beanFactory.getBeanNamesForType(DeferredRepositoryInitializationListener.class)).isNotEmpty(); + assertThat(beanFactory.getBeanNamesForType(AddressRepository.class)).isNotEmpty(); + assertThat(beanFactory.getBeanNamesForType(ProductRepository.class)).isNotEmpty(); } @Test // DATACMNS-1832 @@ -276,9 +286,9 @@ class RepositoryConfigurationDelegateUnitTests { assertThat(it.getGeneric(1).resolve()).isEqualTo(Person.class); } - private static ListableBeanFactory assertLazyRepositoryBeanSetup(Class configClass) { + private static ListableBeanFactory assertLazyRepositoryBeanSetup(Class... componentClasses) { - var context = new AnnotationConfigApplicationContext(configClass); + var context = new AnnotationConfigApplicationContext(componentClasses); assertThat(context.getDefaultListableBeanFactory().getAutowireCandidateResolver()) .isInstanceOf(LazyRepositoryInjectionPointResolver.class); @@ -309,6 +319,12 @@ class RepositoryConfigurationDelegateUnitTests { bootstrapMode = BootstrapMode.DEFERRED) static class DeferredConfig {} + @ComponentScan(basePackageClasses = ProductRepository.class) + @EnableRepositories(basePackageClasses = ProductRepository.class, + includeFilters = @Filter(type = FilterType.ASSIGNABLE_TYPE, classes = AddressRepository.class), + bootstrapMode = BootstrapMode.DEFERRED) + static class OtherDeferredConfig {} + @EnableRepositories(basePackageClasses = MyOtherRepository.class, includeFilters = @Filter(type = FilterType.ASSIGNABLE_TYPE, classes = MyOtherRepository.class), excludeFilters = @Filter(type = FilterType.ASSIGNABLE_TYPE, classes = MyOtherRepositoryImpl.class))