Skip to content

Commit 0cfcbcb

Browse files
committed
Merge pull request #17539 from nosan
* pr/17539: Polish "Ensure Flyway/Liquibase runs before Quartz" Ensure Flyway/Liquibase runs before Quartz Closes gh-17539
2 parents 7150f12 + 75a1a24 commit 0cfcbcb

File tree

2 files changed

+77
-9
lines changed

2 files changed

+77
-9
lines changed

spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/quartz/QuartzAutoConfiguration.java

Lines changed: 41 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121

2222
import javax.sql.DataSource;
2323

24+
import liquibase.integration.spring.SpringLiquibase;
2425
import org.quartz.Calendar;
2526
import org.quartz.JobDetail;
2627
import org.quartz.Scheduler;
@@ -30,11 +31,15 @@
3031
import org.springframework.boot.autoconfigure.AbstractDependsOnBeanFactoryPostProcessor;
3132
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
3233
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
34+
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
3335
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
3436
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
3537
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
3638
import org.springframework.boot.autoconfigure.condition.ConditionalOnSingleCandidate;
39+
import org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration;
40+
import org.springframework.boot.autoconfigure.flyway.FlywayMigrationInitializer;
3741
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
42+
import org.springframework.boot.autoconfigure.liquibase.LiquibaseAutoConfiguration;
3843
import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration;
3944
import org.springframework.boot.context.properties.EnableConfigurationProperties;
4045
import org.springframework.context.ApplicationContext;
@@ -56,7 +61,8 @@
5661
@Configuration
5762
@ConditionalOnClass({ Scheduler.class, SchedulerFactoryBean.class, PlatformTransactionManager.class })
5863
@EnableConfigurationProperties(QuartzProperties.class)
59-
@AutoConfigureAfter({ DataSourceAutoConfiguration.class, HibernateJpaAutoConfiguration.class })
64+
@AutoConfigureAfter({ DataSourceAutoConfiguration.class, HibernateJpaAutoConfiguration.class,
65+
LiquibaseAutoConfiguration.class, FlywayAutoConfiguration.class })
6066
public class QuartzAutoConfiguration {
6167

6268
private final QuartzProperties properties;
@@ -155,22 +161,48 @@ public QuartzDataSourceInitializer quartzDataSourceInitializer(DataSource dataSo
155161
QuartzProperties properties) {
156162
DataSource dataSourceToUse = getDataSource(dataSource, quartzDataSource);
157163
return new QuartzDataSourceInitializer(dataSourceToUse, resourceLoader, properties);
158-
}
159164

160-
@Bean
161-
public static DataSourceInitializerSchedulerDependencyPostProcessor dataSourceInitializerSchedulerDependencyPostProcessor() {
162-
return new DataSourceInitializerSchedulerDependencyPostProcessor();
163165
}
164166

165-
private static class DataSourceInitializerSchedulerDependencyPostProcessor
166-
extends AbstractDependsOnBeanFactoryPostProcessor {
167+
/**
168+
* Additional configuration to ensure that {@link SchedulerFactoryBean} and
169+
* {@link Scheduler} beans depend on the {@link QuartzDataSourceInitializer}
170+
* bean(s).
171+
*/
172+
@Configuration
173+
static class QuartzSchedulerDependencyConfiguration {
174+
175+
@Bean
176+
public static SchedulerDependsOnBeanFactoryPostProcessor quartzSchedulerDataSourceInitializerDependsOnBeanFactoryPostProcessor() {
177+
return new SchedulerDependsOnBeanFactoryPostProcessor(QuartzDataSourceInitializer.class);
178+
}
179+
180+
@Bean
181+
@ConditionalOnBean(FlywayMigrationInitializer.class)
182+
public static SchedulerDependsOnBeanFactoryPostProcessor quartzSchedulerFilywayDependsOnBeanFactoryPostProcessor() {
183+
return new SchedulerDependsOnBeanFactoryPostProcessor(FlywayMigrationInitializer.class);
184+
}
167185

168-
DataSourceInitializerSchedulerDependencyPostProcessor() {
169-
super(Scheduler.class, SchedulerFactoryBean.class, "quartzDataSourceInitializer");
186+
@Bean
187+
@ConditionalOnBean(SpringLiquibase.class)
188+
public static SchedulerDependsOnBeanFactoryPostProcessor quartzSchedulerLiquibaseDependsOnBeanFactoryPostProcessor() {
189+
return new SchedulerDependsOnBeanFactoryPostProcessor(SpringLiquibase.class);
170190
}
171191

172192
}
173193

174194
}
175195

196+
/**
197+
* {@link AbstractDependsOnBeanFactoryPostProcessor} for Quartz {@link Scheduler} and
198+
* {@link SchedulerFactoryBean}.
199+
*/
200+
private static class SchedulerDependsOnBeanFactoryPostProcessor extends AbstractDependsOnBeanFactoryPostProcessor {
201+
202+
SchedulerDependsOnBeanFactoryPostProcessor(Class<?>... dependencyTypes) {
203+
super(Scheduler.class, SchedulerFactoryBean.class, dependencyTypes);
204+
}
205+
206+
}
207+
176208
}

spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/quartz/QuartzAutoConfigurationTests.java

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,16 @@
1616

1717
package org.springframework.boot.autoconfigure.quartz;
1818

19+
import java.io.InputStream;
20+
import java.nio.file.Files;
21+
import java.nio.file.Path;
1922
import java.util.concurrent.Executor;
2023

2124
import javax.sql.DataSource;
2225

2326
import org.junit.Rule;
2427
import org.junit.Test;
28+
import org.junit.rules.TemporaryFolder;
2529
import org.quartz.Calendar;
2630
import org.quartz.JobBuilder;
2731
import org.quartz.JobDetail;
@@ -39,9 +43,11 @@
3943

4044
import org.springframework.beans.factory.annotation.Autowired;
4145
import org.springframework.boot.autoconfigure.AutoConfigurations;
46+
import org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration;
4247
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
4348
import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;
4449
import org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration;
50+
import org.springframework.boot.autoconfigure.liquibase.LiquibaseAutoConfiguration;
4551
import org.springframework.boot.test.context.assertj.AssertableApplicationContext;
4652
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
4753
import org.springframework.boot.test.context.runner.ContextConsumer;
@@ -51,6 +57,7 @@
5157
import org.springframework.context.annotation.Import;
5258
import org.springframework.context.annotation.Primary;
5359
import org.springframework.core.env.Environment;
60+
import org.springframework.core.io.ClassPathResource;
5461
import org.springframework.jdbc.core.JdbcTemplate;
5562
import org.springframework.scheduling.quartz.LocalDataSourceJobStore;
5663
import org.springframework.scheduling.quartz.QuartzJobBean;
@@ -73,6 +80,9 @@ public class QuartzAutoConfigurationTests {
7380
@Rule
7481
public OutputCapture output = new OutputCapture();
7582

83+
@Rule
84+
public TemporaryFolder temp = new TemporaryFolder();
85+
7686
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
7787
.withPropertyValues("spring.datasource.generate-unique-name=true")
7888
.withConfiguration(AutoConfigurations.of(QuartzAutoConfiguration.class));
@@ -243,6 +253,32 @@ public void withCustomConfiguration() {
243253
});
244254
}
245255

256+
@Test
257+
public void withLiquibase() {
258+
this.contextRunner.withUserConfiguration(QuartzJobsConfiguration.class)
259+
.withConfiguration(AutoConfigurations.of(DataSourceAutoConfiguration.class,
260+
DataSourceTransactionManagerAutoConfiguration.class, LiquibaseAutoConfiguration.class))
261+
.withPropertyValues("spring.quartz.job-store-type=jdbc", "spring.quartz.jdbc.initialize-schema=never",
262+
"spring.liquibase.change-log=classpath:org/quartz/impl/jdbcjobstore/liquibase.quartz.init.xml")
263+
.run(assertDataSourceJobStore("dataSource"));
264+
}
265+
266+
@Test
267+
public void withFlyway() throws Exception {
268+
Path flywayLocation = this.temp.newFolder().toPath();
269+
ClassPathResource tablesResource = new ClassPathResource("org/quartz/impl/jdbcjobstore/tables_h2.sql");
270+
try (InputStream stream = tablesResource.getInputStream()) {
271+
Files.copy(stream, flywayLocation.resolve("V2__quartz.sql"));
272+
}
273+
this.contextRunner.withUserConfiguration(QuartzJobsConfiguration.class)
274+
.withConfiguration(AutoConfigurations.of(DataSourceAutoConfiguration.class,
275+
DataSourceTransactionManagerAutoConfiguration.class, FlywayAutoConfiguration.class))
276+
.withPropertyValues("spring.quartz.job-store-type=jdbc", "spring.quartz.jdbc.initialize-schema=never",
277+
"spring.flyway.locations=filesystem:" + flywayLocation,
278+
"spring.flyway.baseline-on-migrate=true")
279+
.run(assertDataSourceJobStore("dataSource"));
280+
}
281+
246282
@Test
247283
public void schedulerNameWithDedicatedProperty() {
248284
this.contextRunner.withPropertyValues("spring.quartz.scheduler-name=testScheduler")

0 commit comments

Comments
 (0)