From 288889685daaae3feab50c8ad8cedaf01b183a9b Mon Sep 17 00:00:00 2001 From: Scott Frederick Date: Tue, 21 Jan 2020 18:06:27 -0600 Subject: [PATCH] Change default BootstrapMode for JPA repositories Change the default `BootstrapMode` for auto-configured `JpaRepositories` to `BootstrapMode.DEFERRED` to allow the initialization of `EntityManagerFactory` to be parallelized for increased startup efficiency. Prior to this change, the default BootstrapMode for all auto-configured Spring Data repositories was `BootstrapMode.DEFAULT`. Closes gh-16230 --- .../jpa/JpaRepositoriesAutoConfiguration.java | 5 +++-- .../data/jpa/JpaRepositoriesRegistrar.java | 5 +++-- ...JpaRepositoriesAutoConfigurationTests.java | 21 ++++++++++++++----- .../autoconfigure/orm/jpa/DataJpaTest.java | 12 ++++++++++- ...ataJpaTestAttributesIntegrationTests.java} | 17 ++++++++++----- .../orm/jpa/DataJpaTestIntegrationTests.java | 10 ++++++++- 6 files changed, 54 insertions(+), 16 deletions(-) rename spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/orm/jpa/{DataJpaTestPropertiesIntegrationTests.java => DataJpaTestAttributesIntegrationTests.java} (66%) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/jpa/JpaRepositoriesAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/jpa/JpaRepositoriesAutoConfiguration.java index f5f345bfa04..69accee93f0 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/jpa/JpaRepositoriesAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/jpa/JpaRepositoriesAutoConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2019 the original author or authors. + * Copyright 2012-2020 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. @@ -56,6 +56,7 @@ import org.springframework.data.jpa.repository.support.JpaRepositoryFactoryBean; * * @author Phillip Webb * @author Josh Long + * @author Scott Frederick * @since 1.0.0 * @see EnableJpaRepositories */ @@ -95,7 +96,7 @@ public class JpaRepositoriesAutoConfiguration { } @ConditionalOnProperty(prefix = "spring.data.jpa.repositories", name = "bootstrap-mode", - havingValue = "deferred", matchIfMissing = false) + havingValue = "deferred", matchIfMissing = true) static class DeferredBootstrapMode { } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/jpa/JpaRepositoriesRegistrar.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/jpa/JpaRepositoriesRegistrar.java index ddc5919ec6b..008250a392b 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/jpa/JpaRepositoriesRegistrar.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/jpa/JpaRepositoriesRegistrar.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2019 the original author or authors. + * Copyright 2012-2020 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. @@ -34,6 +34,7 @@ import org.springframework.util.StringUtils; * * @author Phillip Webb * @author Dave Syer + * @author Scott Frederick */ class JpaRepositoriesRegistrar extends AbstractRepositoryConfigurationSourceSupport { @@ -56,7 +57,7 @@ class JpaRepositoriesRegistrar extends AbstractRepositoryConfigurationSourceSupp @Override protected BootstrapMode getBootstrapMode() { - return (this.bootstrapMode == null) ? super.getBootstrapMode() : this.bootstrapMode; + return (this.bootstrapMode == null) ? BootstrapMode.DEFERRED : this.bootstrapMode; } @Override diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/jpa/JpaRepositoriesAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/jpa/JpaRepositoriesAutoConfigurationTests.java index 6310e6294b1..31f90d94047 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/jpa/JpaRepositoriesAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/jpa/JpaRepositoriesAutoConfigurationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2019 the original author or authors. + * Copyright 2012-2020 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. @@ -51,6 +51,7 @@ import static org.assertj.core.api.Assertions.assertThat; * * @author Dave Syer * @author Oliver Gierke + * @author Scott Frederick */ class JpaRepositoriesAutoConfigurationTests { @@ -85,7 +86,7 @@ class JpaRepositoriesAutoConfigurationTests { } @Test - void whenBootstrappingModeIsLazyWithMultipleAsyncExecutorBootstrapExecutorIsConfigured() { + void whenBootstrapModeIsLazyWithMultipleAsyncExecutorBootstrapExecutorIsConfigured() { this.contextRunner.withUserConfiguration(MultipleAsyncTaskExecutorConfiguration.class) .withConfiguration(AutoConfigurations.of(TaskExecutionAutoConfiguration.class, TaskSchedulingAutoConfiguration.class)) @@ -96,7 +97,7 @@ class JpaRepositoriesAutoConfigurationTests { } @Test - void whenBootstrappingModeIsLazyWithSingleAsyncExecutorBootstrapExecutorIsConfigured() { + void whenBootstrapModeIsLazyWithSingleAsyncExecutorBootstrapExecutorIsConfigured() { this.contextRunner.withUserConfiguration(SingleAsyncTaskExecutorConfiguration.class) .withPropertyValues("spring.data.jpa.repositories.bootstrap-mode=lazy") .run((context) -> assertThat( @@ -105,7 +106,7 @@ class JpaRepositoriesAutoConfigurationTests { } @Test - void whenBootstrappingModeIsDeferredBootstrapExecutorIsConfigured() { + void whenBootstrapModeIsDeferredBootstrapExecutorIsConfigured() { this.contextRunner.withUserConfiguration(MultipleAsyncTaskExecutorConfiguration.class) .withConfiguration(AutoConfigurations.of(TaskExecutionAutoConfiguration.class, TaskSchedulingAutoConfiguration.class)) @@ -116,7 +117,7 @@ class JpaRepositoriesAutoConfigurationTests { } @Test - void whenBootstrappingModeIsDefaultBootstrapExecutorIsNotConfigured() { + void whenBootstrapModeIsDefaultBootstrapExecutorIsNotConfigured() { this.contextRunner.withUserConfiguration(MultipleAsyncTaskExecutorConfiguration.class) .withConfiguration(AutoConfigurations.of(TaskExecutionAutoConfiguration.class, TaskSchedulingAutoConfiguration.class)) @@ -124,6 +125,16 @@ class JpaRepositoriesAutoConfigurationTests { context.getBean(LocalContainerEntityManagerFactoryBean.class).getBootstrapExecutor()).isNull()); } + @Test + void bootstrapModeIsDeferredByDefault() { + this.contextRunner.withUserConfiguration(MultipleAsyncTaskExecutorConfiguration.class) + .withConfiguration(AutoConfigurations.of(TaskExecutionAutoConfiguration.class, + TaskSchedulingAutoConfiguration.class)) + .run((context) -> assertThat( + context.getBean(LocalContainerEntityManagerFactoryBean.class).getBootstrapExecutor()) + .isEqualTo(context.getBean("applicationTaskExecutor"))); + } + @Configuration(proxyBeanMethods = false) @EnableScheduling @Import(TestConfiguration.class) diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/orm/jpa/DataJpaTest.java b/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/orm/jpa/DataJpaTest.java index 7534c4fc5e6..1a9fef2c461 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/orm/jpa/DataJpaTest.java +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/orm/jpa/DataJpaTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2019 the original author or authors. + * Copyright 2012-2020 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. @@ -36,6 +36,7 @@ import org.springframework.boot.test.context.SpringBootTest; import org.springframework.context.annotation.ComponentScan.Filter; import org.springframework.core.annotation.AliasFor; import org.springframework.core.env.Environment; +import org.springframework.data.repository.config.BootstrapMode; import org.springframework.test.context.BootstrapWith; import org.springframework.test.context.junit.jupiter.SpringExtension; import org.springframework.transaction.annotation.Transactional; @@ -62,6 +63,7 @@ import org.springframework.transaction.annotation.Transactional; * * @author Phillip Webb * @author Artsiom Yudovin + * @author Scott Frederick * @since 1.4.0 * @see AutoConfigureDataJpa * @see AutoConfigureTestDatabase @@ -99,6 +101,14 @@ public @interface DataJpaTest { @PropertyMapping("spring.jpa.show-sql") boolean showSql() default true; + /** + * The {@link BootstrapMode} for the test repository support. Defaults to + * {@link BootstrapMode#LAZY}. + * @return the {@link BootstrapMode} to use for test the repository + */ + @PropertyMapping("spring.data.jpa.repositories.bootstrap-mode") + BootstrapMode bootstrapMode() default BootstrapMode.LAZY; + /** * Determines if default filtering should be used with * {@link SpringBootApplication @SpringBootApplication}. By default no beans are diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/orm/jpa/DataJpaTestPropertiesIntegrationTests.java b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/orm/jpa/DataJpaTestAttributesIntegrationTests.java similarity index 66% rename from spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/orm/jpa/DataJpaTestPropertiesIntegrationTests.java rename to spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/orm/jpa/DataJpaTestAttributesIntegrationTests.java index da8567836f4..92ccce3c952 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/orm/jpa/DataJpaTestPropertiesIntegrationTests.java +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/orm/jpa/DataJpaTestAttributesIntegrationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2019 the original author or authors. + * Copyright 2012-2020 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. @@ -20,17 +20,18 @@ import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.core.env.Environment; +import org.springframework.data.repository.config.BootstrapMode; import static org.assertj.core.api.Assertions.assertThat; /** - * Tests for the {@link DataJpaTest#properties properties} attribute of - * {@link DataJpaTest @DataJpaTest}. + * Tests for non-default attributes of {@link DataJpaTest @DataJpaTest}. * * @author Artsiom Yudovin + * @author Scott Frederick */ -@DataJpaTest(properties = "spring.profiles.active=test") -class DataJpaTestPropertiesIntegrationTests { +@DataJpaTest(properties = "spring.profiles.active=test", bootstrapMode = BootstrapMode.DEFERRED) +class DataJpaTestAttributesIntegrationTests { @Autowired private Environment environment; @@ -40,4 +41,10 @@ class DataJpaTestPropertiesIntegrationTests { assertThat(this.environment.getActiveProfiles()).containsExactly("test"); } + @Test + void bootstrapModeIsSet() { + assertThat(this.environment.getProperty("spring.data.jpa.repositories.bootstrap-mode")) + .isEqualTo(BootstrapMode.DEFERRED.name()); + } + } diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/orm/jpa/DataJpaTestIntegrationTests.java b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/orm/jpa/DataJpaTestIntegrationTests.java index 8324341391f..efe3b4aac65 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/orm/jpa/DataJpaTestIntegrationTests.java +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/orm/jpa/DataJpaTestIntegrationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2019 the original author or authors. + * Copyright 2012-2020 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. @@ -25,6 +25,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration; import org.springframework.boot.autoconfigure.liquibase.LiquibaseAutoConfiguration; import org.springframework.context.ApplicationContext; +import org.springframework.data.repository.config.BootstrapMode; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.test.context.TestPropertySource; @@ -37,6 +38,7 @@ import static org.springframework.boot.test.autoconfigure.AutoConfigurationImpor * * @author Phillip Webb * @author Andy Wilkinson + * @author Scott Frederick */ @DataJpaTest @TestPropertySource(properties = "spring.jpa.hibernate.use-new-id-generator-mappings=false") @@ -106,4 +108,10 @@ class DataJpaTestIntegrationTests { assertThat(this.applicationContext).has(importedAutoConfiguration(LiquibaseAutoConfiguration.class)); } + @Test + void bootstrapModeIsLazyByDefault() { + assertThat(this.applicationContext.getEnvironment().getProperty("spring.data.jpa.repositories.bootstrap-mode")) + .isEqualTo(BootstrapMode.LAZY.name()); + } + }