DATACMNS-1368 - Add support for deferred repository initialization.
Both the XML and annotation based configuration sources now support a bootstrap mode configuration property that allow to configure whether repositories are eagerly initialized unless declared as lazy, initialized in a deferred way (just before the application context finishs bootstrapping) or entirely lazy (upon first usage, i.e. a method invocation). We now register a custom AutowireCandidateResolver that will consider all injection points of lazy repositories lazy too. This will prevent them to accidentally trigger downstream infrastructure initialization.
This commit is contained in:
@@ -23,6 +23,7 @@ import lombok.Value;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
@@ -45,6 +46,11 @@ public class DefaultRepositoryConfigurationUnitTests {
|
||||
|
||||
RepositoryConfigurationExtension extension = new SimplerRepositoryConfigurationExtension("factory", "module");
|
||||
|
||||
@Before
|
||||
public void before() {
|
||||
when(source.getBootstrapMode()).thenReturn(BootstrapMode.DEFAULT);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void supportsBasicConfiguration() {
|
||||
|
||||
|
||||
@@ -51,4 +51,6 @@ public @interface EnableRepositories {
|
||||
boolean considerNestedRepositories() default false;
|
||||
|
||||
boolean limitImplementationBasePackages() default true;
|
||||
|
||||
BootstrapMode bootstrapMode() default BootstrapMode.DEFAULT;
|
||||
}
|
||||
|
||||
@@ -49,7 +49,7 @@ public class RepositoryComponentProviderUnitTests {
|
||||
RepositoryComponentProvider provider = new RepositoryComponentProvider(Collections.emptyList(), registry);
|
||||
Set<BeanDefinition> components = provider.findCandidateComponents("org.springframework.data.repository.sample");
|
||||
|
||||
assertThat(components).hasSize(3);
|
||||
assertThat(components).hasSize(4);
|
||||
assertThat(components).extracting(BeanDefinition::getBeanClassName)
|
||||
.contains(SampleAnnotatedRepository.class.getName());
|
||||
}
|
||||
|
||||
@@ -15,18 +15,29 @@
|
||||
*/
|
||||
package org.springframework.data.repository.config;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.hamcrest.CoreMatchers.*;
|
||||
import static org.junit.Assert.*;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.MockitoJUnitRunner;
|
||||
import org.springframework.aop.TargetSource;
|
||||
import org.springframework.aop.framework.Advised;
|
||||
import org.springframework.beans.factory.ListableBeanFactory;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.parsing.BeanComponentDefinition;
|
||||
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
|
||||
import org.springframework.context.annotation.ComponentScan;
|
||||
import org.springframework.context.annotation.ComponentScan.Filter;
|
||||
import org.springframework.context.annotation.FilterType;
|
||||
import org.springframework.context.support.GenericApplicationContext;
|
||||
import org.springframework.core.env.StandardEnvironment;
|
||||
import org.springframework.core.type.StandardAnnotationMetadata;
|
||||
import org.springframework.data.repository.config.RepositoryConfigurationDelegate.LazyRepositoryInjectionPointResolver;
|
||||
import org.springframework.data.repository.sample.AddressRepository;
|
||||
import org.springframework.data.repository.sample.AddressRepositoryClient;
|
||||
import org.springframework.data.repository.sample.ProductRepository;
|
||||
|
||||
/**
|
||||
@@ -35,7 +46,7 @@ import org.springframework.data.repository.sample.ProductRepository;
|
||||
* @author Oliver Gierke
|
||||
* @soundtrack Richard Spaven - Tribute (Whole Other*)
|
||||
*/
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
@RunWith(MockitoJUnitRunner.Silent.class)
|
||||
public class RepositoryConfigurationDelegateUnitTests {
|
||||
|
||||
@Mock RepositoryConfigurationExtension extension;
|
||||
@@ -61,6 +72,51 @@ public class RepositoryConfigurationDelegateUnitTests {
|
||||
}
|
||||
}
|
||||
|
||||
@Test // DATACMNS-1368
|
||||
public void registersLazyAutowireCandidateResolver() {
|
||||
assertLazyRepositoryBeanSetup(LazyConfig.class);
|
||||
}
|
||||
|
||||
@Test // DATACMNS-1368
|
||||
public void registersDeferredRepositoryInitializationListener() {
|
||||
|
||||
ListableBeanFactory beanFactory = assertLazyRepositoryBeanSetup(DeferredConfig.class);
|
||||
|
||||
assertThat(beanFactory.getBeanNamesForType(DeferredRepositoryInitializationListener.class)).isNotEmpty();
|
||||
|
||||
}
|
||||
|
||||
private static ListableBeanFactory assertLazyRepositoryBeanSetup(Class<?> configClass) {
|
||||
|
||||
StandardEnvironment environment = new StandardEnvironment();
|
||||
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(configClass);
|
||||
|
||||
assertThat(context.getDefaultListableBeanFactory().getAutowireCandidateResolver())
|
||||
.isInstanceOf(LazyRepositoryInjectionPointResolver.class);
|
||||
|
||||
AddressRepositoryClient client = context.getBean(AddressRepositoryClient.class);
|
||||
AddressRepository repository = client.getRepository();
|
||||
|
||||
assertThat(Advised.class.isInstance(repository)).isTrue();
|
||||
|
||||
TargetSource targetSource = Advised.class.cast(repository).getTargetSource();
|
||||
assertThat(targetSource).isNotNull();
|
||||
|
||||
return context.getDefaultListableBeanFactory();
|
||||
}
|
||||
|
||||
@EnableRepositories(basePackageClasses = ProductRepository.class)
|
||||
static class TestConfig {}
|
||||
|
||||
@ComponentScan(basePackageClasses = AddressRepository.class)
|
||||
@EnableRepositories(basePackageClasses = AddressRepository.class,
|
||||
includeFilters = @Filter(type = FilterType.ASSIGNABLE_TYPE, classes = AddressRepository.class),
|
||||
bootstrapMode = BootstrapMode.LAZY)
|
||||
static class LazyConfig {}
|
||||
|
||||
@ComponentScan(basePackageClasses = AddressRepository.class)
|
||||
@EnableRepositories(basePackageClasses = AddressRepository.class,
|
||||
includeFilters = @Filter(type = FilterType.ASSIGNABLE_TYPE, classes = AddressRepository.class),
|
||||
bootstrapMode = BootstrapMode.DEFERRED)
|
||||
static class DeferredConfig {}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Copyright 2018 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.repository.sample;
|
||||
|
||||
import org.springframework.data.repository.Repository;
|
||||
import org.springframework.data.repository.sample.AddressRepository.Address;
|
||||
|
||||
/**
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public interface AddressRepository extends Repository<Address, Long> {
|
||||
|
||||
static class Address {}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright 2018 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.repository.sample;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
public class AddressRepositoryClient {
|
||||
|
||||
private final @Getter AddressRepository repository;
|
||||
}
|
||||
Reference in New Issue
Block a user