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 3e9d06f180..1ad3d6fbda 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 @@ -90,6 +90,8 @@ public class QuartzAutoConfiguration { SchedulerFactoryBean schedulerFactoryBean = new SchedulerFactoryBean(); schedulerFactoryBean.setJobFactory(new AutowireCapableBeanJobFactory( this.applicationContext.getAutowireCapableBeanFactory())); + schedulerFactoryBean + .setOverwriteExistingJobs(this.properties.isOverwriteExistingJobs()); if (!this.properties.getProperties().isEmpty()) { schedulerFactoryBean .setQuartzProperties(asProperties(this.properties.getProperties())); diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/quartz/QuartzProperties.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/quartz/QuartzProperties.java index de33c0e8e5..1151a480ae 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/quartz/QuartzProperties.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/quartz/QuartzProperties.java @@ -37,6 +37,11 @@ public class QuartzProperties { */ private JobStoreType jobStoreType = JobStoreType.MEMORY; + /** + * Whether configured jobs should overwrite existing job definitions. + */ + private boolean overwriteExistingJobs = false; + /** * Additional Quartz Scheduler properties. */ @@ -52,6 +57,14 @@ public class QuartzProperties { this.jobStoreType = jobStoreType; } + public boolean isOverwriteExistingJobs() { + return this.overwriteExistingJobs; + } + + public void setOverwriteExistingJobs(boolean overwriteExistingJobs) { + this.overwriteExistingJobs = overwriteExistingJobs; + } + public Map getProperties() { return this.properties; } 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 1d65a888de..3052eac929 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 @@ -29,6 +29,7 @@ import org.quartz.JobExecutionContext; import org.quartz.JobKey; import org.quartz.Scheduler; import org.quartz.SimpleScheduleBuilder; +import org.quartz.SimpleTrigger; import org.quartz.Trigger; import org.quartz.TriggerBuilder; import org.quartz.TriggerKey; @@ -158,6 +159,21 @@ public class QuartzAutoConfigurationTests { }); } + @Test + public void withOverwriteExistingJobs() { + this.contextRunner.withUserConfiguration(OverwriteTriggerConfiguration.class) + .withPropertyValues("spring.quartz.overwrite-existing-jobs=true") + .run((context) -> { + assertThat(context).hasSingleBean(Scheduler.class); + Scheduler scheduler = context.getBean(Scheduler.class); + Trigger fooTrigger = scheduler + .getTrigger(TriggerKey.triggerKey("fooTrigger")); + assertThat(fooTrigger).isNotNull(); + assertThat(((SimpleTrigger) fooTrigger).getRepeatInterval()) + .isEqualTo(30000); + }); + } + @Test public void withConfiguredJobAndTrigger() { this.contextRunner.withUserConfiguration(QuartzFullConfiguration.class) @@ -251,6 +267,21 @@ public class QuartzAutoConfigurationTests { } + @Configuration + @Import(QuartzFullConfiguration.class) + protected static class OverwriteTriggerConfiguration extends BaseQuartzConfiguration { + + @Bean + public Trigger anotherFooTrigger(JobDetail fooJob) { + SimpleScheduleBuilder scheduleBuilder = SimpleScheduleBuilder.simpleSchedule() + .withIntervalInSeconds(30).repeatForever(); + + return TriggerBuilder.newTrigger().forJob(fooJob).withIdentity("fooTrigger") + .withSchedule(scheduleBuilder).build(); + } + + } + @Configuration protected static class QuartzCalendarsConfiguration extends BaseQuartzConfiguration { diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc index be06a22a28..9882fcf46d 100644 --- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc +++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc @@ -146,6 +146,7 @@ content into your application. Rather, pick only the properties that you need. spring.quartz.jdbc.schema=classpath:org/quartz/impl/jdbcjobstore/tables_@@platform@@.sql # Path to the SQL file to use to initialize the database schema. spring.quartz.job-store-type=memory # Quartz job store type. spring.quartz.properties.*= # Additional Quartz Scheduler properties. + spring.quartz.overwrite-existing-jobs=false # Whether configured jobs should overwrite existing job definitions. # REACTOR ({sc-spring-boot-autoconfigure}/reactor/core/ReactorCoreProperties.{sc-ext}[ReactorCoreProperties]) spring.reactor.stacktrace-mode.enabled=false # Whether Reactor should collect stacktrace information at runtime. 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 82411c5f2f..bd75661aab 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 @@ -5996,8 +5996,12 @@ NOTE: By default, the database is detected and initialized by using the standard provided with the Quartz library. It is also possible to provide a custom script by setting the `spring.quartz.jdbc.schema` property. +By default, jobs created by configuration will not overwrite already registered jobs that +have been read from a persistent job store. To enable overwriting existing job definitions +set the `spring.quartz.overwrite-existing-jobs` property. + Quartz Scheduler configuration can be customized by using Quartz configuration properties -()`spring.quartz.properties.*`) and `SchedulerFactoryBeanCustomizer` beans, which allow +(`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