DATACMNS-609 - Improved bean definition registration for repository configuration.

The bean definitions that were registered for a repository configuration setup we registered once for every usage of the repository configuration element (annotation or XML). This caused multiple registrations of the very same bean definition which - as in case of the RepositoryInterfaceAwareBeanPostProcessor - apparently leads to performance problems in the container startup. Feedback for the latter claim is already asked for but we improved the registration setup nonetheless.

Introduced a registerIfNotAlreadyRegistered(…) method on RepositoryConfigurationExtensionSupport to allow easy registration of to-b-registered-once-and-only-once beans. We now hint towards the newly introduced method in registerWithSourceAndGeneratedBeanName(…).
This commit is contained in:
Oliver Gierke
2014-11-30 17:58:16 +01:00
parent 447aca6e9c
commit 0cb1cca588
2 changed files with 57 additions and 6 deletions

View File

@@ -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.

View File

@@ -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<PlainType, Long> {}
@EnableRepositories
static class SampleConfiguration {}
}