From e4e56bbcc3e4242497a9ad9b89414e7e96230b13 Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Thu, 12 Apr 2018 15:23:36 +0200 Subject: [PATCH 1/2] Migrate to ApplicationContextRunner --- .../quartz/QuartzAutoConfigurationTests.java | 276 ++++++++++-------- 1 file changed, 147 insertions(+), 129 deletions(-) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/quartz/QuartzAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/quartz/QuartzAutoConfigurationTests.java index 8fe619355c2..c1eaf917dc9 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/quartz/QuartzAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/quartz/QuartzAutoConfigurationTests.java @@ -21,8 +21,6 @@ import java.util.concurrent.Executors; import javax.sql.DataSource; -import com.zaxxer.hikari.HikariDataSource; -import org.junit.After; import org.junit.Rule; import org.junit.Test; import org.quartz.Calendar; @@ -31,7 +29,6 @@ import org.quartz.JobDetail; import org.quartz.JobExecutionContext; import org.quartz.JobKey; import org.quartz.Scheduler; -import org.quartz.SchedulerException; import org.quartz.SimpleScheduleBuilder; import org.quartz.Trigger; import org.quartz.TriggerBuilder; @@ -42,13 +39,14 @@ import org.quartz.simpl.RAMJobStore; import org.quartz.simpl.SimpleThreadPool; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.AutoConfigurations; +import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; +import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties; import org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration; -import org.springframework.boot.autoconfigure.jdbc.EmbeddedDataSourceConfiguration; -import org.springframework.boot.jdbc.DataSourceBuilder; +import org.springframework.boot.test.context.assertj.AssertableApplicationContext; +import org.springframework.boot.test.context.runner.ApplicationContextRunner; +import org.springframework.boot.test.context.runner.ContextConsumer; import org.springframework.boot.test.rule.OutputCapture; -import org.springframework.boot.test.util.TestPropertyValues; -import org.springframework.context.ConfigurableApplicationContext; -import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; @@ -59,7 +57,6 @@ import org.springframework.scheduling.quartz.LocalDataSourceJobStore; import org.springframework.scheduling.quartz.LocalTaskExecutorThreadPool; import org.springframework.scheduling.quartz.QuartzJobBean; import org.springframework.util.Assert; -import org.springframework.util.ObjectUtils; import static org.assertj.core.api.Assertions.assertThat; import static org.hamcrest.CoreMatchers.containsString; @@ -75,163 +72,178 @@ public class QuartzAutoConfigurationTests { @Rule public OutputCapture output = new OutputCapture(); - private ConfigurableApplicationContext context; - - @After - public void closeContext() { - if (this.context != null) { - this.context.close(); - } - } + private final ApplicationContextRunner contextRunner = new ApplicationContextRunner() + .withPropertyValues("spring.datasource.generate-unique-name=true") + .withConfiguration(AutoConfigurations.of(QuartzAutoConfiguration.class)); @Test - public void withNoDataSource() throws Exception { - load(); - assertThat(this.context.getBeansOfType(Scheduler.class)).hasSize(1); - Scheduler scheduler = this.context.getBean(Scheduler.class); - assertThat(scheduler.getMetaData().getJobStoreClass()) - .isAssignableFrom(RAMJobStore.class); + public void withNoDataSource() { + this.contextRunner.run((context) -> { + assertThat(context).hasSingleBean(Scheduler.class); + Scheduler scheduler = context.getBean(Scheduler.class); + assertThat(scheduler.getMetaData().getJobStoreClass()) + .isAssignableFrom(RAMJobStore.class); + }); } @Test - public void withDataSourceUseMemoryByDefault() throws Exception { - load(new Class[] { EmbeddedDataSourceConfiguration.class, - DataSourceTransactionManagerAutoConfiguration.class }); - assertThat(this.context.getBeansOfType(Scheduler.class)).hasSize(1); - Scheduler scheduler = this.context.getBean(Scheduler.class); - assertThat(scheduler.getMetaData().getJobStoreClass()) - .isAssignableFrom(RAMJobStore.class); + public void withDataSourceUseMemoryByDefault() { + this.contextRunner.withConfiguration(AutoConfigurations.of( + DataSourceAutoConfiguration.class, + DataSourceTransactionManagerAutoConfiguration.class)).run((context) -> { + assertThat(context).hasSingleBean(Scheduler.class); + Scheduler scheduler = context.getBean(Scheduler.class); + assertThat(scheduler.getMetaData().getJobStoreClass()) + .isAssignableFrom(RAMJobStore.class); + }); } @Test - public void withDataSource() throws Exception { - load(new Class[] { QuartzJobsConfiguration.class, - EmbeddedDataSourceConfiguration.class, - DataSourceTransactionManagerAutoConfiguration.class }, - "spring.quartz.job-store-type=jdbc"); - testWithDataSource(); + public void withDataSource() { + this.contextRunner.withUserConfiguration(QuartzJobsConfiguration.class) + .withConfiguration(AutoConfigurations.of(DataSourceAutoConfiguration.class, + DataSourceTransactionManagerAutoConfiguration.class)) + .withPropertyValues("spring.quartz.job-store-type=jdbc") + .run(assertDataSourceJobStore("dataSource")); } @Test - public void withDataSourceNoTransactionManager() throws Exception { - load(new Class[] { QuartzJobsConfiguration.class, - EmbeddedDataSourceConfiguration.class }, - "spring.quartz.job-store-type=jdbc"); - testWithDataSource(); - } - - private void testWithDataSource() throws SchedulerException { - assertThat(this.context.getBeansOfType(Scheduler.class)).hasSize(1); - Scheduler scheduler = this.context.getBean(Scheduler.class); - assertThat(scheduler.getMetaData().getJobStoreClass()) - .isAssignableFrom(LocalDataSourceJobStore.class); - JdbcTemplate jdbcTemplate = new JdbcTemplate( - this.context.getBean(DataSource.class)); - assertThat(jdbcTemplate.queryForObject("SELECT COUNT(*) FROM QRTZ_JOB_DETAILS", - Integer.class)).isEqualTo(2); - assertThat(jdbcTemplate.queryForObject( - "SELECT COUNT(*) FROM QRTZ_SIMPLE_TRIGGERS", Integer.class)).isEqualTo(0); + public void withDataSourceNoTransactionManager() { + this.contextRunner.withUserConfiguration(QuartzJobsConfiguration.class) + .withConfiguration(AutoConfigurations.of( + DataSourceAutoConfiguration.class)) + .withPropertyValues("spring.quartz.job-store-type=jdbc") + .run(assertDataSourceJobStore("dataSource")); } @Test - public void withTaskExecutor() throws Exception { - load(QuartzExecutorConfiguration.class); - assertThat(this.context.getBeansOfType(Scheduler.class)).hasSize(1); - Scheduler scheduler = this.context.getBean(Scheduler.class); - assertThat(scheduler.getMetaData().getThreadPoolClass()) - .isEqualTo(LocalTaskExecutorThreadPool.class); + public void dataSourceWithQuartzDataSourceQualifierUsedWhenMultiplePresent() { + this.contextRunner + .withUserConfiguration(QuartzJobsConfiguration.class, + MultipleDataSourceConfiguration.class) + .withPropertyValues("spring.quartz.job-store-type=jdbc") + .run(assertDataSourceJobStore("quartzDataSource")); } - @Test - public void withMultipleTaskExecutors() throws Exception { - load(QuartzMultipleExecutorsConfiguration.class); - assertThat(this.context.getBeansOfType(Executor.class)).hasSize(2); - assertThat(this.context.getBeansOfType(Scheduler.class)).hasSize(1); - Scheduler scheduler = this.context.getBean(Scheduler.class); - assertThat(scheduler.getMetaData().getThreadPoolClass()) - .isEqualTo(SimpleThreadPool.class); + private ContextConsumer assertDataSourceJobStore( + String datasourceName) { + return (context) -> { + assertThat(context).hasSingleBean(Scheduler.class); + Scheduler scheduler = context.getBean(Scheduler.class); + assertThat(scheduler.getMetaData().getJobStoreClass()) + .isAssignableFrom(LocalDataSourceJobStore.class); + JdbcTemplate jdbcTemplate = new JdbcTemplate(context.getBean( + datasourceName, DataSource.class)); + assertThat(jdbcTemplate.queryForObject( + "SELECT COUNT(*) FROM QRTZ_JOB_DETAILS", Integer.class)).isEqualTo(2); + assertThat(jdbcTemplate.queryForObject( + "SELECT COUNT(*) FROM QRTZ_SIMPLE_TRIGGERS", Integer.class)) + .isEqualTo(0); + }; } @Test - public void withMultipleTaskExecutorsWithPrimary() throws Exception { - load(QuartzMultipleExecutorsWithPrimaryConfiguration.class); - assertThat(this.context.getBeansOfType(Executor.class)).hasSize(2); - assertThat(this.context.getBeansOfType(Scheduler.class)).hasSize(1); - Scheduler scheduler = this.context.getBean(Scheduler.class); - assertThat(scheduler.getMetaData().getThreadPoolClass()) - .isEqualTo(LocalTaskExecutorThreadPool.class); + public void withTaskExecutor() { + this.contextRunner.withUserConfiguration(QuartzExecutorConfiguration.class) + .run((context) -> { + assertThat(context).hasSingleBean(Scheduler.class); + Scheduler scheduler = context.getBean(Scheduler.class); + assertThat(scheduler.getMetaData().getThreadPoolClass()) + .isEqualTo(LocalTaskExecutorThreadPool.class); + }); } @Test - public void withMultipleTaskExecutorsWithCustomizer() throws Exception { - load(QuartzMultipleExecutorsWithCustomizerConfiguration.class); - assertThat(this.context.getBeansOfType(Executor.class)).hasSize(3); - assertThat(this.context.getBeansOfType(Scheduler.class)).hasSize(1); - Scheduler scheduler = this.context.getBean(Scheduler.class); - assertThat(scheduler.getMetaData().getThreadPoolClass()) - .isEqualTo(LocalTaskExecutorThreadPool.class); + public void withMultipleTaskExecutors() { + this.contextRunner + .withUserConfiguration(QuartzMultipleExecutorsConfiguration.class) + .run((context) -> { + assertThat(context.getBeansOfType(Executor.class)).hasSize(2); + assertThat(context).hasSingleBean(Scheduler.class); + Scheduler scheduler = context.getBean(Scheduler.class); + assertThat(scheduler.getMetaData().getThreadPoolClass()) + .isEqualTo(SimpleThreadPool.class); + }); } @Test - public void withConfiguredJobAndTrigger() throws Exception { - load(QuartzFullConfiguration.class, "test-name=withConfiguredJobAndTrigger"); - assertThat(this.context.getBeansOfType(Scheduler.class)).hasSize(1); - Scheduler scheduler = this.context.getBean(Scheduler.class); - assertThat(scheduler.getJobDetail(JobKey.jobKey("fooJob"))).isNotNull(); - assertThat(scheduler.getTrigger(TriggerKey.triggerKey("fooTrigger"))).isNotNull(); - Thread.sleep(1000L); - this.output.expect(containsString("withConfiguredJobAndTrigger")); - this.output.expect(containsString("jobDataValue")); + public void withMultipleTaskExecutorsWithPrimary() { + this.contextRunner + .withUserConfiguration( + QuartzMultipleExecutorsWithPrimaryConfiguration.class) + .run((context) -> { + assertThat(context.getBeansOfType(Executor.class)).hasSize(2); + assertThat(context).hasSingleBean(Scheduler.class); + Scheduler scheduler = context.getBean(Scheduler.class); + assertThat(scheduler.getMetaData().getThreadPoolClass()) + .isEqualTo(LocalTaskExecutorThreadPool.class); + }); } @Test - public void withConfiguredCalendars() throws Exception { - load(QuartzCalendarsConfiguration.class); - assertThat(this.context.getBeansOfType(Scheduler.class)).hasSize(1); - Scheduler scheduler = this.context.getBean(Scheduler.class); - assertThat(scheduler.getCalendar("weekly")).isNotNull(); - assertThat(scheduler.getCalendar("monthly")).isNotNull(); + public void withMultipleTaskExecutorsWithCustomizer() { + this.contextRunner + .withUserConfiguration( + QuartzMultipleExecutorsWithCustomizerConfiguration.class) + .run((context) -> { + assertThat(context.getBeansOfType(Executor.class)).hasSize(3); + assertThat(context).hasSingleBean(Scheduler.class); + Scheduler scheduler = context.getBean(Scheduler.class); + assertThat(scheduler.getMetaData().getThreadPoolClass()) + .isEqualTo(LocalTaskExecutorThreadPool.class); + }); } @Test - public void withQuartzProperties() throws Exception { - load("spring.quartz.properties.org.quartz.scheduler.instanceId=FOO"); - assertThat(this.context.getBeansOfType(Scheduler.class)).hasSize(1); - Scheduler scheduler = this.context.getBean(Scheduler.class); - assertThat(scheduler.getSchedulerInstanceId()).isEqualTo("FOO"); + public void withConfiguredJobAndTrigger() { + this.contextRunner.withUserConfiguration(QuartzFullConfiguration.class) + .withPropertyValues("test-name=withConfiguredJobAndTrigger") + .run((context) -> { + assertThat(context).hasSingleBean(Scheduler.class); + Scheduler scheduler = context.getBean(Scheduler.class); + assertThat(scheduler.getJobDetail(JobKey.jobKey("fooJob"))) + .isNotNull(); + assertThat(scheduler.getTrigger(TriggerKey.triggerKey("fooTrigger"))) + .isNotNull(); + Thread.sleep(1000L); + this.output.expect(containsString("withConfiguredJobAndTrigger")); + this.output.expect(containsString("jobDataValue")); + }); } @Test - public void withCustomizer() throws Exception { - load(QuartzCustomConfiguration.class); - assertThat(this.context.getBeansOfType(Scheduler.class)).hasSize(1); - Scheduler scheduler = this.context.getBean(Scheduler.class); - assertThat(scheduler.getSchedulerName()).isEqualTo("fooScheduler"); + public void withConfiguredCalendars() { + this.contextRunner.withUserConfiguration(QuartzCalendarsConfiguration.class) + .run((context) -> { + assertThat(context).hasSingleBean(Scheduler.class); + Scheduler scheduler = context.getBean(Scheduler.class); + assertThat(scheduler.getCalendar("weekly")).isNotNull(); + assertThat(scheduler.getCalendar("monthly")).isNotNull(); + }); } @Test - public void dataSourceWithQuartzDataSourceQualifierUsedWhenMultiplePresent() { - load(MultipleDataSourceConfiguration.class, "spring.quartz.job-store-type=jdbc"); + public void withQuartzProperties() { + this.contextRunner.withPropertyValues( + "spring.quartz.properties.org.quartz.scheduler.instanceId=FOO") + .run((context) -> { + assertThat(context).hasSingleBean(Scheduler.class); + Scheduler scheduler = context.getBean(Scheduler.class); + assertThat(scheduler.getSchedulerInstanceId()).isEqualTo("FOO"); + }); } - private void load(String... environment) { - load(new Class[0], environment); + @Test + public void withCustomizer() { + this.contextRunner.withUserConfiguration(QuartzCustomConfiguration.class) + .run((context) -> { + assertThat(context).hasSingleBean(Scheduler.class); + Scheduler scheduler = context.getBean(Scheduler.class); + assertThat(scheduler.getSchedulerName()).isEqualTo("fooScheduler"); + }); } - private void load(Class config, String... environment) { - load(new Class[] { config }, environment); - } - private void load(Class[] configs, String... environment) { - AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(); - TestPropertyValues.of(environment).applyTo(ctx); - if (!ObjectUtils.isEmpty(configs)) { - ctx.register(configs); - } - ctx.register(QuartzAutoConfiguration.class); - ctx.refresh(); - this.context = ctx; - } @Import(ComponentThatUsesScheduler.class) @Configuration @@ -358,15 +370,21 @@ public class QuartzAutoConfigurationTests { @Bean @Primary - public DataSource applicationDataSource() { - return new HikariDataSource(); + public DataSource applicationDataSource() throws Exception { + return createTestDataSource(); } @QuartzDataSource @Bean - public DataSource quartzDataSource() { - return DataSourceBuilder.create().url("jdbc:hsqldb:mem:quartztest") - .username("sa").build(); + public DataSource quartzDataSource() throws Exception { + return createTestDataSource(); + } + + private DataSource createTestDataSource() throws Exception { + DataSourceProperties properties = new DataSourceProperties(); + properties.setGenerateUniqueName(true); + properties.afterPropertiesSet(); + return properties.initializeDataSourceBuilder().build(); } } From 38bd4bd58cbd5c34c64ca4db65e8797db4f0fb86 Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Thu, 12 Apr 2018 15:41:15 +0200 Subject: [PATCH 2/2] Stop associating an Executor bean to Quartz This commits make sure that the Quartz auto-configuration no longer associates an `Executor` bean if present in the context as Quartz offers properties to tune it, which would mutate and lead to unexpected results. Closes gh-12823 --- .../quartz/QuartzAutoConfiguration.java | 9 +- .../quartz/QuartzAutoConfigurationTests.java | 99 ++----------------- .../main/asciidoc/spring-boot-features.adoc | 4 + 3 files changed, 15 insertions(+), 97 deletions(-) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/quartz/QuartzAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/quartz/QuartzAutoConfiguration.java index 76936be4765..dbc5475407a 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/quartz/QuartzAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/quartz/QuartzAutoConfiguration.java @@ -19,7 +19,6 @@ package org.springframework.boot.autoconfigure.quartz; import java.util.List; import java.util.Map; import java.util.Properties; -import java.util.concurrent.Executor; import javax.sql.DataSource; @@ -64,8 +63,6 @@ public class QuartzAutoConfiguration { private final List customizers; - private final Executor taskExecutor; - private final JobDetail[] jobDetails; private final Map calendars; @@ -76,12 +73,11 @@ public class QuartzAutoConfiguration { public QuartzAutoConfiguration(QuartzProperties properties, ObjectProvider> customizers, - ObjectProvider taskExecutor, ObjectProvider jobDetails, + ObjectProvider jobDetails, ObjectProvider> calendars, ObjectProvider triggers, ApplicationContext applicationContext) { this.properties = properties; this.customizers = customizers.getIfAvailable(); - this.taskExecutor = taskExecutor.getIfUnique(); this.jobDetails = jobDetails.getIfAvailable(); this.calendars = calendars.getIfAvailable(); this.triggers = triggers.getIfAvailable(); @@ -98,9 +94,6 @@ public class QuartzAutoConfiguration { schedulerFactoryBean .setQuartzProperties(asProperties(this.properties.getProperties())); } - if (this.taskExecutor != null) { - schedulerFactoryBean.setTaskExecutor(this.taskExecutor); - } if (this.jobDetails != null && this.jobDetails.length > 0) { schedulerFactoryBean.setJobDetails(this.jobDetails); } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/quartz/QuartzAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/quartz/QuartzAutoConfigurationTests.java index c1eaf917dc9..eb6e4ce21e7 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/quartz/QuartzAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/quartz/QuartzAutoConfigurationTests.java @@ -17,7 +17,6 @@ package org.springframework.boot.autoconfigure.quartz; import java.util.concurrent.Executor; -import java.util.concurrent.Executors; import javax.sql.DataSource; @@ -36,7 +35,6 @@ import org.quartz.TriggerKey; import org.quartz.impl.calendar.MonthlyCalendar; import org.quartz.impl.calendar.WeeklyCalendar; import org.quartz.simpl.RAMJobStore; -import org.quartz.simpl.SimpleThreadPool; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.AutoConfigurations; @@ -54,12 +52,13 @@ import org.springframework.context.annotation.Primary; import org.springframework.core.env.Environment; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.scheduling.quartz.LocalDataSourceJobStore; -import org.springframework.scheduling.quartz.LocalTaskExecutorThreadPool; import org.springframework.scheduling.quartz.QuartzJobBean; import org.springframework.util.Assert; import static org.assertj.core.api.Assertions.assertThat; import static org.hamcrest.CoreMatchers.containsString; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verifyZeroInteractions; /** * Tests for {@link QuartzAutoConfiguration}. @@ -144,53 +143,15 @@ public class QuartzAutoConfigurationTests { @Test public void withTaskExecutor() { - this.contextRunner.withUserConfiguration(QuartzExecutorConfiguration.class) + this.contextRunner.withUserConfiguration(MockExecutorConfiguration.class) + .withPropertyValues( + "spring.quartz.properties.org.quartz.threadPool.threadCount=50") .run((context) -> { assertThat(context).hasSingleBean(Scheduler.class); Scheduler scheduler = context.getBean(Scheduler.class); - assertThat(scheduler.getMetaData().getThreadPoolClass()) - .isEqualTo(LocalTaskExecutorThreadPool.class); - }); - } - - @Test - public void withMultipleTaskExecutors() { - this.contextRunner - .withUserConfiguration(QuartzMultipleExecutorsConfiguration.class) - .run((context) -> { - assertThat(context.getBeansOfType(Executor.class)).hasSize(2); - assertThat(context).hasSingleBean(Scheduler.class); - Scheduler scheduler = context.getBean(Scheduler.class); - assertThat(scheduler.getMetaData().getThreadPoolClass()) - .isEqualTo(SimpleThreadPool.class); - }); - } - - @Test - public void withMultipleTaskExecutorsWithPrimary() { - this.contextRunner - .withUserConfiguration( - QuartzMultipleExecutorsWithPrimaryConfiguration.class) - .run((context) -> { - assertThat(context.getBeansOfType(Executor.class)).hasSize(2); - assertThat(context).hasSingleBean(Scheduler.class); - Scheduler scheduler = context.getBean(Scheduler.class); - assertThat(scheduler.getMetaData().getThreadPoolClass()) - .isEqualTo(LocalTaskExecutorThreadPool.class); - }); - } - - @Test - public void withMultipleTaskExecutorsWithCustomizer() { - this.contextRunner - .withUserConfiguration( - QuartzMultipleExecutorsWithCustomizerConfiguration.class) - .run((context) -> { - assertThat(context.getBeansOfType(Executor.class)).hasSize(3); - assertThat(context).hasSingleBean(Scheduler.class); - Scheduler scheduler = context.getBean(Scheduler.class); - assertThat(scheduler.getMetaData().getThreadPoolClass()) - .isEqualTo(LocalTaskExecutorThreadPool.class); + assertThat(scheduler.getMetaData().getThreadPoolSize()).isEqualTo(50); + Executor executor = context.getBean(Executor.class); + verifyZeroInteractions(executor); }); } @@ -304,51 +265,11 @@ public class QuartzAutoConfigurationTests { } @Configuration - protected static class QuartzExecutorConfiguration extends BaseQuartzConfiguration { + protected static class MockExecutorConfiguration extends BaseQuartzConfiguration { @Bean public Executor executor() { - return Executors.newSingleThreadExecutor(); - } - - } - - @Configuration - protected static class QuartzMultipleExecutorsConfiguration - extends QuartzExecutorConfiguration { - - @Bean - public Executor anotherExecutor() { - return Executors.newSingleThreadExecutor(); - } - - } - - @Configuration - protected static class QuartzMultipleExecutorsWithPrimaryConfiguration - extends QuartzExecutorConfiguration { - - @Bean - @Primary - public Executor primaryExecutor() { - return Executors.newSingleThreadExecutor(); - } - - } - - @Configuration - protected static class QuartzMultipleExecutorsWithCustomizerConfiguration - extends QuartzMultipleExecutorsConfiguration { - - @Bean - public Executor yetAnotherExecutor() { - return Executors.newSingleThreadExecutor(); - } - - @Bean - public SchedulerFactoryBeanCustomizer customizer() { - return (schedulerFactoryBean) -> schedulerFactoryBean - .setTaskExecutor(yetAnotherExecutor()); + return mock(Executor.class); } } diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc index 604a3ee2f1f..77e50153919 100644 --- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc +++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc @@ -5876,6 +5876,10 @@ Quartz Scheduler configuration can be customized by using Quartz configuration p ()`spring.quartz.properties.*`) and `SchedulerFactoryBeanCustomizer` beans, which allow programmatic `SchedulerFactoryBean` customization. +NOTE: In particular, an `Executor` bean is not associated with the scheduler as Quartz +offers a way to configure the scheduler via `spring.quartz.properties`. If you need +to customize the task executor, consider implementing `SchedulerFactoryBeanCustomizer`. + Jobs can define setters to inject data map properties. Regular beans can also be injected in a similar manner, as shown in the following example: