From bf3437f39c3577c0cf9e4290d0f9546cc1afeff4 Mon Sep 17 00:00:00 2001 From: Oliver Gierke Date: Sun, 12 Jan 2014 23:13:32 +0100 Subject: [PATCH] DATACMNS-415 - Performance improvements in configuration subsystem. Changed the design of RepositoryBeanDefinitionBuilder to receive stable dependencies in the constructor and the moving parts as method arguments. This enables us to reuse the builder instance for the creation of all repository bean definitions. Most importantly that means we can use a single CachingMetadataReaderFactory instance which will avoid reading files again when looking for custom implementation classes. Adapted clients for XML configuration and JavaConfig accordingly. --- .../RepositoryBeanDefinitionBuilder.java | 38 +++++++++++-------- .../RepositoryBeanDefinitionParser.java | 15 +++++--- ...ositoryBeanDefinitionRegistrarSupport.java | 16 ++++---- 3 files changed, 40 insertions(+), 29 deletions(-) diff --git a/src/main/java/org/springframework/data/repository/config/RepositoryBeanDefinitionBuilder.java b/src/main/java/org/springframework/data/repository/config/RepositoryBeanDefinitionBuilder.java index 53bf83ad3..ccffed703 100644 --- a/src/main/java/org/springframework/data/repository/config/RepositoryBeanDefinitionBuilder.java +++ b/src/main/java/org/springframework/data/repository/config/RepositoryBeanDefinitionBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2013 the original author or authors. + * Copyright 2012-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. @@ -29,6 +29,8 @@ import org.springframework.beans.factory.support.BeanDefinitionBuilder; import org.springframework.beans.factory.support.BeanDefinitionRegistry; import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider; import org.springframework.core.io.ResourceLoader; +import org.springframework.core.type.classreading.CachingMetadataReaderFactory; +import org.springframework.core.type.classreading.MetadataReaderFactory; import org.springframework.core.type.filter.RegexPatternTypeFilter; import org.springframework.util.Assert; import org.springframework.util.StringUtils; @@ -42,24 +44,29 @@ public class RepositoryBeanDefinitionBuilder { private static final Logger LOGGER = LoggerFactory.getLogger(RepositoryBeanDefinitionBuilder.class); - private final RepositoryConfiguration configuration; + private final BeanDefinitionRegistry registry; private final RepositoryConfigurationExtension extension; + private final ResourceLoader resourceLoader; + + private final MetadataReaderFactory metadataReaderFactory; /** - * Creates a new {@link RepositoryBeanDefinitionBuilder} from the given {@link RepositoryConfiguration} and - * {@link RepositoryConfigurationExtension}. + * Creates a new {@link RepositoryBeanDefinitionBuilder} from the given {@link BeanDefinitionRegistry}, + * {@link RepositoryConfigurationExtension} and {@link ResourceLoader}. * - * @param configuration must not be {@literal null}. + * @param registry must not be {@literal null}. * @param extension must not be {@literal null}. + * @param resourceLoader must not be {@literal null}. */ - public RepositoryBeanDefinitionBuilder(RepositoryConfiguration configuration, - RepositoryConfigurationExtension extension) { + public RepositoryBeanDefinitionBuilder(BeanDefinitionRegistry registry, RepositoryConfigurationExtension extension, + ResourceLoader resourceLoader) { - Assert.notNull(configuration); Assert.notNull(extension); - this.configuration = configuration; + this.registry = registry; this.extension = extension; + this.resourceLoader = resourceLoader; + this.metadataReaderFactory = new CachingMetadataReaderFactory(resourceLoader); } /** @@ -70,7 +77,7 @@ public class RepositoryBeanDefinitionBuilder { * @param resourceLoader must not be {@literal null}. * @return */ - public BeanDefinitionBuilder build(BeanDefinitionRegistry registry, ResourceLoader resourceLoader) { + public BeanDefinitionBuilder build(RepositoryConfiguration configuration) { Assert.notNull(registry, "BeanDefinitionRegistry must not be null!"); Assert.notNull(resourceLoader, "ResourceLoader must not be null!"); @@ -95,7 +102,7 @@ public class RepositoryBeanDefinitionBuilder { builder.addPropertyValue("namedQueries", definitionBuilder.build(configuration.getSource())); - String customImplementationBeanName = registerCustomImplementation(registry, resourceLoader); + String customImplementationBeanName = registerCustomImplementation(configuration); if (customImplementationBeanName != null) { builder.addPropertyReference("customImplementation", customImplementationBeanName); @@ -105,7 +112,7 @@ public class RepositoryBeanDefinitionBuilder { return builder; } - private String registerCustomImplementation(BeanDefinitionRegistry registry, ResourceLoader resourceLoader) { + private String registerCustomImplementation(RepositoryConfiguration configuration) { String beanName = configuration.getImplementationBeanName(); @@ -114,7 +121,7 @@ public class RepositoryBeanDefinitionBuilder { return beanName; } - AbstractBeanDefinition beanDefinition = detectCustomImplementation(registry, resourceLoader); + AbstractBeanDefinition beanDefinition = detectCustomImplementation(configuration); if (null == beanDefinition) { return null; @@ -139,14 +146,15 @@ public class RepositoryBeanDefinitionBuilder { * @param parser * @return the {@code AbstractBeanDefinition} of the custom implementation or {@literal null} if none found */ - private AbstractBeanDefinition detectCustomImplementation(BeanDefinitionRegistry registry, ResourceLoader loader) { + private AbstractBeanDefinition detectCustomImplementation(RepositoryConfiguration configuration) { // Build pattern to lookup implementation class Pattern pattern = Pattern.compile(".*\\." + configuration.getImplementationClassName()); // Build classpath scanner and lookup bean definition ClassPathScanningCandidateComponentProvider provider = new ClassPathScanningCandidateComponentProvider(false); - provider.setResourceLoader(loader); + provider.setResourceLoader(resourceLoader); + provider.setMetadataReaderFactory(metadataReaderFactory); provider.addIncludeFilter(new RegexPatternTypeFilter(pattern)); Set definitions = new HashSet(); diff --git a/src/main/java/org/springframework/data/repository/config/RepositoryBeanDefinitionParser.java b/src/main/java/org/springframework/data/repository/config/RepositoryBeanDefinitionParser.java index c1eef8669..1ccb349cb 100644 --- a/src/main/java/org/springframework/data/repository/config/RepositoryBeanDefinitionParser.java +++ b/src/main/java/org/springframework/data/repository/config/RepositoryBeanDefinitionParser.java @@ -1,5 +1,5 @@ /* - * Copyright 2008-2013 the original author or authors. + * Copyright 2008-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. @@ -28,6 +28,7 @@ import org.springframework.beans.factory.support.BeanDefinitionRegistry; import org.springframework.beans.factory.xml.BeanDefinitionParser; import org.springframework.beans.factory.xml.ParserContext; import org.springframework.core.env.Environment; +import org.springframework.core.io.ResourceLoader; import org.springframework.util.Assert; import org.w3c.dom.Element; @@ -94,13 +95,15 @@ public class RepositoryBeanDefinitionParser implements BeanDefinitionParser { private void registerGenericRepositoryFactoryBean( RepositoryConfiguration configuration, ParserContext parser) { - RepositoryBeanDefinitionBuilder definitionBuilder = new RepositoryBeanDefinitionBuilder(configuration, extension); + ResourceLoader resourceLoader = parser.getReaderContext().getResourceLoader(); + BeanDefinitionRegistry registry = parser.getRegistry(); + + RepositoryBeanDefinitionBuilder definitionBuilder = new RepositoryBeanDefinitionBuilder(registry, extension, + resourceLoader); try { - BeanDefinitionBuilder builder = definitionBuilder.build(parser.getRegistry(), parser.getReaderContext() - .getResourceLoader()); - + BeanDefinitionBuilder builder = definitionBuilder.build(configuration); extension.postProcess(builder, configuration.getConfigurationSource()); AbstractBeanDefinition beanDefinition = builder.getBeanDefinition(); @@ -109,7 +112,7 @@ public class RepositoryBeanDefinitionParser implements BeanDefinitionParser { RepositoryBeanNameGenerator generator = new RepositoryBeanNameGenerator(); generator.setBeanClassLoader(parser.getReaderContext().getBeanClassLoader()); - String beanName = generator.generateBeanName(beanDefinition, parser.getRegistry()); + String beanName = generator.generateBeanName(beanDefinition, registry); if (LOGGER.isDebugEnabled()) { LOGGER.debug("Registering repository: " + beanName + " - Interface: " + configuration.getRepositoryInterface() diff --git a/src/main/java/org/springframework/data/repository/config/RepositoryBeanDefinitionRegistrarSupport.java b/src/main/java/org/springframework/data/repository/config/RepositoryBeanDefinitionRegistrarSupport.java index fe0fddcfb..d49e65ea8 100644 --- a/src/main/java/org/springframework/data/repository/config/RepositoryBeanDefinitionRegistrarSupport.java +++ b/src/main/java/org/springframework/data/repository/config/RepositoryBeanDefinitionRegistrarSupport.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2013 the original author or authors. + * Copyright 2012-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. @@ -87,22 +87,22 @@ public abstract class RepositoryBeanDefinitionRegistrarSupport implements Import defaultExternalResources(registry); - AnnotationRepositoryConfigurationSource configuration = new AnnotationRepositoryConfigurationSource( + AnnotationRepositoryConfigurationSource configurationSource = new AnnotationRepositoryConfigurationSource( annotationMetadata, getAnnotation(), environment); RepositoryConfigurationExtension extension = getExtension(); - extension.registerBeansForRoot(registry, configuration); + extension.registerBeansForRoot(registry, configurationSource); RepositoryBeanNameGenerator generator = new RepositoryBeanNameGenerator(); generator.setBeanClassLoader(beanClassLoader); - for (RepositoryConfiguration repositoryConfiguration : extension - .getRepositoryConfigurations(configuration, resourceLoader)) { + RepositoryBeanDefinitionBuilder builder = new RepositoryBeanDefinitionBuilder(registry, extension, resourceLoader); - RepositoryBeanDefinitionBuilder builder = new RepositoryBeanDefinitionBuilder(repositoryConfiguration, extension); - BeanDefinitionBuilder definitionBuilder = builder.build(registry, resourceLoader); + for (RepositoryConfiguration configuration : extension + .getRepositoryConfigurations(configurationSource, resourceLoader)) { - extension.postProcess(definitionBuilder, configuration); + BeanDefinitionBuilder definitionBuilder = builder.build(configuration); + extension.postProcess(definitionBuilder, configurationSource); String beanName = generator.generateBeanName(definitionBuilder.getBeanDefinition(), registry); registry.registerBeanDefinition(beanName, definitionBuilder.getBeanDefinition());