Skip to content

Commit 42be28e

Browse files
Startup metrics for per module repository scanning.
This commit adds application startup metrics for the time taken to scan the context for Spring Data repositories on a per module (JPA, MongoDB,...) base. We capture the module name, the scan base package and the number of repositories found. { "startupStep": { "name": "spring.data.repository.scanning", "id": ..., "parentId": ..., "tags": [ { "key": "data-module", "value": "MongoDB" }, { "key": "packages", "value": "com.example.demo" }, { "key": "repository.count", "value": "1" } ] } }
1 parent e4db978 commit 42be28e

File tree

2 files changed

+52
-2
lines changed

2 files changed

+52
-2
lines changed

src/main/java/org/springframework/data/repository/config/RepositoryConfigurationDelegate.java

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525

2626
import org.apache.commons.logging.Log;
2727
import org.apache.commons.logging.LogFactory;
28-
28+
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
2929
import org.springframework.beans.factory.config.DependencyDescriptor;
3030
import org.springframework.beans.factory.parsing.BeanComponentDefinition;
3131
import org.springframework.beans.factory.support.AbstractBeanDefinition;
@@ -34,12 +34,15 @@
3434
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
3535
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
3636
import org.springframework.context.annotation.ContextAnnotationAutowireCandidateResolver;
37+
import org.springframework.context.support.GenericApplicationContext;
3738
import org.springframework.core.env.Environment;
3839
import org.springframework.core.env.EnvironmentCapable;
3940
import org.springframework.core.env.StandardEnvironment;
4041
import org.springframework.core.io.ResourceLoader;
4142
import org.springframework.core.io.support.SpringFactoriesLoader;
4243
import org.springframework.core.log.LogMessage;
44+
import org.springframework.core.metrics.ApplicationStartup;
45+
import org.springframework.core.metrics.StartupStep;
4346
import org.springframework.data.repository.core.support.RepositoryFactorySupport;
4447
import org.springframework.lang.Nullable;
4548
import org.springframework.util.Assert;
@@ -143,6 +146,11 @@ public List<BeanComponentDefinition> registerRepositoriesIn(BeanDefinitionRegist
143146
configurationSource.getBasePackages().stream().collect(Collectors.joining(", "))));
144147
}
145148

149+
ApplicationStartup startup = getStartup(registry);
150+
StartupStep repoScan = startup.start("spring.data.repository.scanning");
151+
repoScan.tag("data-module", extension.getModuleName());
152+
repoScan.tag("packages", configurationSource.getBasePackages().stream().collect(Collectors.joining(", ")));
153+
146154
watch.start();
147155

148156
Collection<RepositoryConfiguration<RepositoryConfigurationSource>> configurations = extension
@@ -184,6 +192,9 @@ public List<BeanComponentDefinition> registerRepositoriesIn(BeanDefinitionRegist
184192

185193
watch.stop();
186194

195+
repoScan.tag("repository.count", Integer.toString(configurations.size()));
196+
repoScan.end();
197+
187198
if (logger.isInfoEnabled()) {
188199
logger.info(LogMessage.format("Finished Spring Data repository scanning in %s ms. Found %s %s repository interfaces.", //
189200
watch.getLastTaskTimeMillis(), configurations.size(), extension.getModuleName()));
@@ -208,7 +219,6 @@ private static void potentiallyLazifyRepositories(Map<String, RepositoryConfigur
208219
}
209220

210221
DefaultListableBeanFactory beanFactory = DefaultListableBeanFactory.class.cast(registry);
211-
212222
AutowireCandidateResolver resolver = beanFactory.getAutowireCandidateResolver();
213223

214224
if (!Arrays.asList(ContextAnnotationAutowireCandidateResolver.class, LazyRepositoryInjectionPointResolver.class)
@@ -253,6 +263,23 @@ private boolean multipleStoresDetected() {
253263
return multipleModulesFound;
254264
}
255265

266+
ApplicationStartup getStartup(BeanDefinitionRegistry registry) {
267+
268+
if(ConfigurableBeanFactory.class.isInstance(registry)) {
269+
return ((ConfigurableBeanFactory)registry).getApplicationStartup();
270+
}
271+
272+
if (DefaultListableBeanFactory.class.isInstance(registry)) {
273+
return ((DefaultListableBeanFactory)registry).getBeanProvider(ApplicationStartup.class).getIfAvailable(() -> ApplicationStartup.DEFAULT);
274+
}
275+
276+
if(GenericApplicationContext.class.isInstance(registry)) {
277+
return ((GenericApplicationContext)registry).getDefaultListableBeanFactory().getApplicationStartup();
278+
}
279+
280+
return ApplicationStartup.DEFAULT;
281+
}
282+
256283
/**
257284
* Customer {@link ContextAnnotationAutowireCandidateResolver} that also considers all injection points for lazy
258285
* repositories lazy.

src/test/java/org/springframework/data/repository/config/RepositoryConfigurationDelegateUnitTests.java

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import org.junit.jupiter.api.Test;
2121
import org.junit.jupiter.api.extension.ExtendWith;
2222
import org.mockito.Mock;
23+
import org.mockito.Mockito;
2324
import org.mockito.junit.jupiter.MockitoExtension;
2425
import org.mockito.junit.jupiter.MockitoSettings;
2526
import org.mockito.quality.Strictness;
@@ -35,6 +36,8 @@
3536
import org.springframework.context.annotation.FilterType;
3637
import org.springframework.context.support.GenericApplicationContext;
3738
import org.springframework.core.env.StandardEnvironment;
39+
import org.springframework.core.metrics.ApplicationStartup;
40+
import org.springframework.core.metrics.StartupStep;
3841
import org.springframework.core.type.StandardAnnotationMetadata;
3942
import org.springframework.data.repository.config.RepositoryConfigurationDelegate.LazyRepositoryInjectionPointResolver;
4043
import org.springframework.data.repository.sample.AddressRepository;
@@ -107,6 +110,26 @@ private static ListableBeanFactory assertLazyRepositoryBeanSetup(Class<?> config
107110
return context.getDefaultListableBeanFactory();
108111
}
109112

113+
@Test // DATACMNS-1832
114+
void writesRepositoryScanningMetrics() {
115+
116+
ApplicationStartup startup = Mockito.spy(ApplicationStartup.DEFAULT);
117+
118+
StandardEnvironment environment = new StandardEnvironment();
119+
GenericApplicationContext context = new GenericApplicationContext();
120+
context.setApplicationStartup(startup);
121+
122+
RepositoryConfigurationSource configSource = new AnnotationRepositoryConfigurationSource(
123+
new StandardAnnotationMetadata(TestConfig.class, true), EnableRepositories.class, context, environment,
124+
context.getDefaultListableBeanFactory());
125+
126+
RepositoryConfigurationDelegate delegate = new RepositoryConfigurationDelegate(configSource, context, environment);
127+
128+
delegate.registerRepositoriesIn(context, extension);
129+
130+
Mockito.verify(startup).start("spring.data.repository.scanning");
131+
}
132+
110133
@EnableRepositories(basePackageClasses = ProductRepository.class)
111134
static class TestConfig {}
112135

0 commit comments

Comments
 (0)