Skip to content

Commit c5ff21a

Browse files
committed
Merge pull request #4299 from vpavic:quartz-scheduler-support
* pr/4299: Polish "Add Quartz Scheduler support" Add Quartz Scheduler support
2 parents da6647c + 59a15b2 commit c5ff21a

File tree

23 files changed

+1037
-1
lines changed

23 files changed

+1037
-1
lines changed

spring-boot-autoconfigure/pom.xml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -656,6 +656,11 @@
656656
<artifactId>narayana-jts-integration</artifactId>
657657
<optional>true</optional>
658658
</dependency>
659+
<dependency>
660+
<groupId>org.quartz-scheduler</groupId>
661+
<artifactId>quartz</artifactId>
662+
<optional>true</optional>
663+
</dependency>
659664
<!-- Annotation processing -->
660665
<dependency>
661666
<groupId>org.springframework.boot</groupId>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
/*
2+
* Copyright 2012-2017 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.boot.autoconfigure.quartz;
18+
19+
import org.quartz.spi.TriggerFiredBundle;
20+
21+
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
22+
import org.springframework.scheduling.quartz.SpringBeanJobFactory;
23+
import org.springframework.util.Assert;
24+
25+
/**
26+
* Subclass of {@link SpringBeanJobFactory} that supports auto-wiring job beans.
27+
*
28+
* @author Vedran Pavic
29+
* @since 2.0.0
30+
* @see <a href="http://blog.btmatthews.com/?p=40#comment-33797"> Inject application
31+
* context dependencies in Quartz job beans</a>
32+
*/
33+
class AutowireCapableBeanJobFactory extends SpringBeanJobFactory {
34+
35+
private final AutowireCapableBeanFactory beanFactory;
36+
37+
AutowireCapableBeanJobFactory(AutowireCapableBeanFactory beanFactory) {
38+
Assert.notNull(beanFactory, "Bean factory must not be null");
39+
this.beanFactory = beanFactory;
40+
}
41+
42+
@Override
43+
protected Object createJobInstance(TriggerFiredBundle bundle) throws Exception {
44+
Object jobInstance = super.createJobInstance(bundle);
45+
this.beanFactory.autowireBean(jobInstance);
46+
this.beanFactory.initializeBean(jobInstance, null);
47+
return jobInstance;
48+
}
49+
50+
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
/*
2+
* Copyright 2012-2017 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.boot.autoconfigure.quartz;
18+
19+
/**
20+
* Define the supported Quartz {@code JobStore}.
21+
*
22+
* @author Stephane Nicoll
23+
* @since 2.0.0
24+
*/
25+
public enum JobStoreType {
26+
27+
/**
28+
* Store jobs in memory.
29+
*/
30+
MEMORY,
31+
32+
/**
33+
* Store jobs in the database.
34+
*/
35+
JDBC
36+
37+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,161 @@
1+
/*
2+
* Copyright 2012-2017 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.boot.autoconfigure.quartz;
18+
19+
import java.util.List;
20+
import java.util.Map;
21+
import java.util.Properties;
22+
import java.util.concurrent.Executor;
23+
24+
import javax.sql.DataSource;
25+
26+
import org.quartz.Calendar;
27+
import org.quartz.JobDetail;
28+
import org.quartz.Scheduler;
29+
import org.quartz.Trigger;
30+
31+
import org.springframework.beans.factory.ObjectProvider;
32+
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
33+
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
34+
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
35+
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
36+
import org.springframework.boot.autoconfigure.condition.ConditionalOnSingleCandidate;
37+
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
38+
import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration;
39+
import org.springframework.boot.context.properties.EnableConfigurationProperties;
40+
import org.springframework.context.ApplicationContext;
41+
import org.springframework.context.annotation.Bean;
42+
import org.springframework.context.annotation.Configuration;
43+
import org.springframework.core.io.ResourceLoader;
44+
import org.springframework.scheduling.quartz.SchedulerFactoryBean;
45+
import org.springframework.transaction.PlatformTransactionManager;
46+
47+
/**
48+
* {@link EnableAutoConfiguration Auto-configuration} for Quartz Scheduler.
49+
*
50+
* @author Vedran Pavic
51+
* @author Stephane Nicoll
52+
* @since 2.0.0
53+
*/
54+
@Configuration
55+
@ConditionalOnClass({ Scheduler.class, SchedulerFactoryBean.class,
56+
PlatformTransactionManager.class })
57+
@EnableConfigurationProperties(QuartzProperties.class)
58+
@AutoConfigureAfter({ DataSourceAutoConfiguration.class,
59+
HibernateJpaAutoConfiguration.class })
60+
public class QuartzAutoConfiguration {
61+
62+
private final QuartzProperties properties;
63+
64+
private final List<SchedulerFactoryBeanCustomizer> customizers;
65+
66+
private final Executor taskExecutor;
67+
68+
private final JobDetail[] jobDetails;
69+
70+
private final Map<String, Calendar> calendars;
71+
72+
private final Trigger[] triggers;
73+
74+
private final ApplicationContext applicationContext;
75+
76+
public QuartzAutoConfiguration(QuartzProperties properties,
77+
ObjectProvider<List<SchedulerFactoryBeanCustomizer>> customizers,
78+
ObjectProvider<Executor> taskExecutor, ObjectProvider<JobDetail[]> jobDetails,
79+
ObjectProvider<Map<String, Calendar>> calendars,
80+
ObjectProvider<Trigger[]> triggers,
81+
ApplicationContext applicationContext) {
82+
this.properties = properties;
83+
this.customizers = customizers.getIfAvailable();
84+
this.taskExecutor = taskExecutor.getIfAvailable();
85+
this.jobDetails = jobDetails.getIfAvailable();
86+
this.calendars = calendars.getIfAvailable();
87+
this.triggers = triggers.getIfAvailable();
88+
this.applicationContext = applicationContext;
89+
}
90+
91+
@Bean
92+
@ConditionalOnSingleCandidate(DataSource.class)
93+
@ConditionalOnMissingBean
94+
public QuartzDatabaseInitializer quartzDatabaseInitializer(DataSource dataSource,
95+
ResourceLoader resourceLoader) {
96+
return new QuartzDatabaseInitializer(dataSource, resourceLoader, this.properties);
97+
}
98+
99+
@Bean
100+
@ConditionalOnMissingBean
101+
public SchedulerFactoryBean quartzScheduler() {
102+
SchedulerFactoryBean schedulerFactoryBean = new SchedulerFactoryBean();
103+
schedulerFactoryBean.setJobFactory(new AutowireCapableBeanJobFactory(
104+
this.applicationContext.getAutowireCapableBeanFactory()));
105+
if (!this.properties.getProperties().isEmpty()) {
106+
schedulerFactoryBean
107+
.setQuartzProperties(asProperties(this.properties.getProperties()));
108+
}
109+
if (this.taskExecutor != null) {
110+
schedulerFactoryBean.setTaskExecutor(this.taskExecutor);
111+
}
112+
if (this.jobDetails != null && this.jobDetails.length > 0) {
113+
schedulerFactoryBean.setJobDetails(this.jobDetails);
114+
}
115+
if (this.calendars != null && !this.calendars.isEmpty()) {
116+
schedulerFactoryBean.setCalendars(this.calendars);
117+
}
118+
if (this.triggers != null && this.triggers.length > 0) {
119+
schedulerFactoryBean.setTriggers(this.triggers);
120+
}
121+
customize(schedulerFactoryBean);
122+
return schedulerFactoryBean;
123+
}
124+
125+
private Properties asProperties(Map<String, String> source) {
126+
Properties properties = new Properties();
127+
properties.putAll(source);
128+
return properties;
129+
}
130+
131+
private void customize(SchedulerFactoryBean schedulerFactoryBean) {
132+
if (this.customizers != null) {
133+
for (SchedulerFactoryBeanCustomizer customizer : this.customizers) {
134+
customizer.customize(schedulerFactoryBean);
135+
}
136+
}
137+
}
138+
139+
@Configuration
140+
@ConditionalOnSingleCandidate(DataSource.class)
141+
protected static class JdbcStoreTypeConfiguration {
142+
143+
@Bean
144+
public SchedulerFactoryBeanCustomizer dataSourceCustomizer(
145+
QuartzProperties properties, DataSource dataSource,
146+
ObjectProvider<PlatformTransactionManager> transactionManager) {
147+
return schedulerFactoryBean -> {
148+
if (properties.getJobStoreType() == JobStoreType.JDBC) {
149+
schedulerFactoryBean.setDataSource(dataSource);
150+
PlatformTransactionManager txManager =
151+
transactionManager.getIfUnique();
152+
if (txManager != null) {
153+
schedulerFactoryBean.setTransactionManager(txManager);
154+
}
155+
}
156+
};
157+
}
158+
159+
}
160+
161+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
/*
2+
* Copyright 2012-2017 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.boot.autoconfigure.quartz;
18+
19+
import javax.sql.DataSource;
20+
21+
import org.springframework.boot.autoconfigure.AbstractDatabaseInitializer;
22+
import org.springframework.core.io.ResourceLoader;
23+
import org.springframework.util.Assert;
24+
25+
/**
26+
* Initializer for Quartz Scheduler schema.
27+
*
28+
* @author Vedran Pavic
29+
* @since 2.0.0
30+
*/
31+
public class QuartzDatabaseInitializer extends AbstractDatabaseInitializer {
32+
33+
private final QuartzProperties properties;
34+
35+
public QuartzDatabaseInitializer(DataSource dataSource, ResourceLoader resourceLoader,
36+
QuartzProperties properties) {
37+
super(dataSource, resourceLoader);
38+
Assert.notNull(properties, "QuartzProperties must not be null");
39+
this.properties = properties;
40+
}
41+
42+
@Override
43+
protected boolean isEnabled() {
44+
return this.properties.getJdbc().isInitializeSchema();
45+
}
46+
47+
@Override
48+
protected String getSchemaLocation() {
49+
return this.properties.getJdbc().getSchema();
50+
}
51+
52+
@Override
53+
protected String getDatabaseName() {
54+
String databaseName = super.getDatabaseName();
55+
if ("db2".equals(databaseName)) {
56+
return "db2_v95";
57+
}
58+
if ("mysql".equals(databaseName)) {
59+
return "mysql_innodb";
60+
}
61+
if ("postgresql".equals(databaseName)) {
62+
return "postgres";
63+
}
64+
if ("sqlserver".equals(databaseName)) {
65+
return "sqlServer";
66+
}
67+
return databaseName;
68+
}
69+
70+
}

0 commit comments

Comments
 (0)