DATACMNS-1172 - Limit repository custom implementation scanning by default to repository interface packages.

Custom repository implementation scan defaults to the repository interface package and its subpackages and no longer scans all configured base packages. Scan for fragment implementations defaults to the fragment interface package. Using the interface package for scanning aligns the behavior with the documentation.

This default can be changed with @Enable…Repositories annotations that support the limitImplementationBasePackages parameter to scan in repository base packages for custom implementations:

@EnableJpaRepositories(limitImplementationBasePackages = false)
@Configuration
class AppConfiguration {
  // …
}

Declaring the implementation along with the interface in the same package is an established design pattern allowing to limit the scanning scope. A limited scope improves scanning performance as it can skip elements on the classpath, that do not provide that particular package.

Previously, we scanned for implementations using the configured base packages that were also used to discover repository interfaces. These base packages can be broader for applications that spread repository interfaces across multiple packages.
This commit is contained in:
Mark Paluch
2017-09-27 09:43:45 +02:00
committed by Oliver Gierke
parent 2220bed116
commit 3bae636e2f
14 changed files with 208 additions and 8 deletions

View File

@@ -53,6 +53,7 @@ import org.springframework.util.StringUtils;
* @author Thomas Darimont
* @author Peter Rietzler
* @author Jens Schauder
* @author Mark Paluch
*/
public class AnnotationRepositoryConfigurationSource extends RepositoryConfigurationSourceSupport {
@@ -64,6 +65,7 @@ public class AnnotationRepositoryConfigurationSource extends RepositoryConfigura
private static final String REPOSITORY_FACTORY_BEAN_CLASS = "repositoryFactoryBeanClass";
private static final String REPOSITORY_BASE_CLASS = "repositoryBaseClass";
private static final String CONSIDER_NESTED_REPOSITORIES = "considerNestedRepositories";
private static final String LIMIT_IMPLEMENTATION_BASE_PACKAGES = "limitImplementationBasePackages";
private final AnnotationMetadata configMetadata;
private final AnnotationMetadata enableAnnotationMetadata;
@@ -320,6 +322,20 @@ public class AnnotationRepositoryConfigurationSource extends RepositoryConfigura
return attributes.containsKey(CONSIDER_NESTED_REPOSITORIES) && attributes.getBoolean(CONSIDER_NESTED_REPOSITORIES);
}
/*
* (non-Javadoc)
* @see org.springframework.data.repository.config.RepositoryConfigurationSourceSupport#shouldLimitRepositoryImplementationBasePackages()
*/
@Override
public boolean shouldLimitRepositoryImplementationBasePackages() {
if (!attributes.containsKey(LIMIT_IMPLEMENTATION_BASE_PACKAGES)) {
return true;
}
return attributes.getBoolean(LIMIT_IMPLEMENTATION_BASE_PACKAGES);
}
/*
* (non-Javadoc)
* @see org.springframework.data.repository.config.RepositoryConfigurationSource#getAttribute(java.lang.String)

View File

@@ -46,6 +46,7 @@ import org.springframework.util.Assert;
* @author Christoph Strobl
* @author Peter Rietzler
* @author Jens Schauder
* @author Mark Paluch
*/
@RequiredArgsConstructor
public class CustomRepositoryImplementationDetector {
@@ -71,7 +72,7 @@ public class CustomRepositoryImplementationDetector {
return detectCustomImplementation( //
configuration.getImplementationClassName(), //
configuration.getImplementationBeanName(), //
configuration.getBasePackages(), //
configuration.getImplementationBasePackages(configuration.getImplementationClassName()), //
configuration.getExcludeFilters(), //
bd -> configuration.getConfigurationSource().generateBeanName(bd));
}

View File

@@ -34,6 +34,7 @@ import org.springframework.util.StringUtils;
*
* @author Oliver Gierke
* @author Jens Schauder
* @author Mark Paluch
*/
@RequiredArgsConstructor
public class DefaultRepositoryConfiguration<T extends RepositoryConfigurationSource>
@@ -71,6 +72,18 @@ public class DefaultRepositoryConfiguration<T extends RepositoryConfigurationSou
return configurationSource.getBasePackages();
}
/*
* (non-Javadoc)
* @see org.springframework.data.repository.config.RepositoryConfiguration#getBasePackages(String)
*/
@Override
public Streamable<String> getImplementationBasePackages(String interfaceClassName) {
return configurationSource.shouldLimitRepositoryImplementationBasePackages()
? Streamable.of(ClassUtils.getPackageName(interfaceClassName))
: getBasePackages();
}
/*
* (non-Javadoc)
* @see org.springframework.data.repository.config.RepositoryConfiguration#getRepositoryInterface()

View File

@@ -202,7 +202,8 @@ class RepositoryBeanDefinitionBuilder {
.concat(configuration.getConfigurationSource().getRepositoryImplementationPostfix().orElse("Impl"));
Optional<AbstractBeanDefinition> beanDefinition = implementationDetector.detectCustomImplementation(className, null,
configuration.getBasePackages(), exclusions, bd -> configuration.getConfigurationSource().generateBeanName(bd));
configuration.getImplementationBasePackages(fragmentInterfaceName), exclusions,
bd -> configuration.getConfigurationSource().generateBeanName(bd));
return beanDefinition.map(bd -> new RepositoryFragmentConfiguration(fragmentInterfaceName, bd));
}

View File

@@ -37,6 +37,15 @@ public interface RepositoryConfiguration<T extends RepositoryConfigurationSource
*/
Streamable<String> getBasePackages();
/**
* Returns the base packages to scan for repository implementations.
*
* @param interfaceClassName class name of the interface.
* @return
* @since 2.0
*/
Streamable<String> getImplementationBasePackages(String interfaceClassName);
/**
* Returns the interface name of the repository.
*

View File

@@ -31,6 +31,7 @@ import org.springframework.lang.Nullable;
* @author Thomas Darimont
* @author Peter Rietzler
* @author Jens Schauder
* @author Mark Paluch
*/
public interface RepositoryConfigurationSource {
@@ -62,6 +63,17 @@ public interface RepositoryConfigurationSource {
*/
Optional<String> getRepositoryImplementationPostfix();
/**
* Returns whether to limit repository implementation base packages for custom implementation scanning. If
* {@literal true}, then custom implementation scanning considers only the package of the repository/fragment
* interface and its subpackages for a scan. Otherwise, all {@link #getBasePackages()} are scanned for repository
* implementations
*
* @return {@literal true} if base packages are limited to the actual repository package.
* @since 2.0
*/
boolean shouldLimitRepositoryImplementationBasePackages();
/**
* @return
*/

View File

@@ -117,4 +117,13 @@ public abstract class RepositoryConfigurationSourceSupport implements Repository
public boolean shouldConsiderNestedRepositories() {
return false;
}
/*
* (non-Javadoc)
* @see org.springframework.data.repository.config.RepositoryConfigurationSource#isLimitRepositoryImplementationBasePackages()
*/
@Override
public boolean shouldLimitRepositoryImplementationBasePackages() {
return true;
}
}