Merge pull request #4299 from vpavic:quartz-scheduler-support
* pr/4299: Polish "Add Quartz Scheduler support" Add Quartz Scheduler supportpull/4487/merge
commit
c5ff21a4d3
@ -0,0 +1,50 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2012-2017 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.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.springframework.boot.autoconfigure.quartz;
|
||||||
|
|
||||||
|
import org.quartz.spi.TriggerFiredBundle;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
|
||||||
|
import org.springframework.scheduling.quartz.SpringBeanJobFactory;
|
||||||
|
import org.springframework.util.Assert;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Subclass of {@link SpringBeanJobFactory} that supports auto-wiring job beans.
|
||||||
|
*
|
||||||
|
* @author Vedran Pavic
|
||||||
|
* @since 2.0.0
|
||||||
|
* @see <a href="http://blog.btmatthews.com/?p=40#comment-33797"> Inject application
|
||||||
|
* context dependencies in Quartz job beans</a>
|
||||||
|
*/
|
||||||
|
class AutowireCapableBeanJobFactory extends SpringBeanJobFactory {
|
||||||
|
|
||||||
|
private final AutowireCapableBeanFactory beanFactory;
|
||||||
|
|
||||||
|
AutowireCapableBeanJobFactory(AutowireCapableBeanFactory beanFactory) {
|
||||||
|
Assert.notNull(beanFactory, "Bean factory must not be null");
|
||||||
|
this.beanFactory = beanFactory;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Object createJobInstance(TriggerFiredBundle bundle) throws Exception {
|
||||||
|
Object jobInstance = super.createJobInstance(bundle);
|
||||||
|
this.beanFactory.autowireBean(jobInstance);
|
||||||
|
this.beanFactory.initializeBean(jobInstance, null);
|
||||||
|
return jobInstance;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,37 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2012-2017 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.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.springframework.boot.autoconfigure.quartz;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Define the supported Quartz {@code JobStore}.
|
||||||
|
*
|
||||||
|
* @author Stephane Nicoll
|
||||||
|
* @since 2.0.0
|
||||||
|
*/
|
||||||
|
public enum JobStoreType {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Store jobs in memory.
|
||||||
|
*/
|
||||||
|
MEMORY,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Store jobs in the database.
|
||||||
|
*/
|
||||||
|
JDBC
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,161 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2012-2017 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.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
import org.quartz.Calendar;
|
||||||
|
import org.quartz.JobDetail;
|
||||||
|
import org.quartz.Scheduler;
|
||||||
|
import org.quartz.Trigger;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.ObjectProvider;
|
||||||
|
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
|
||||||
|
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||||
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||||
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||||
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnSingleCandidate;
|
||||||
|
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
|
||||||
|
import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration;
|
||||||
|
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||||
|
import org.springframework.context.ApplicationContext;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.core.io.ResourceLoader;
|
||||||
|
import org.springframework.scheduling.quartz.SchedulerFactoryBean;
|
||||||
|
import org.springframework.transaction.PlatformTransactionManager;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@link EnableAutoConfiguration Auto-configuration} for Quartz Scheduler.
|
||||||
|
*
|
||||||
|
* @author Vedran Pavic
|
||||||
|
* @author Stephane Nicoll
|
||||||
|
* @since 2.0.0
|
||||||
|
*/
|
||||||
|
@Configuration
|
||||||
|
@ConditionalOnClass({ Scheduler.class, SchedulerFactoryBean.class,
|
||||||
|
PlatformTransactionManager.class })
|
||||||
|
@EnableConfigurationProperties(QuartzProperties.class)
|
||||||
|
@AutoConfigureAfter({ DataSourceAutoConfiguration.class,
|
||||||
|
HibernateJpaAutoConfiguration.class })
|
||||||
|
public class QuartzAutoConfiguration {
|
||||||
|
|
||||||
|
private final QuartzProperties properties;
|
||||||
|
|
||||||
|
private final List<SchedulerFactoryBeanCustomizer> customizers;
|
||||||
|
|
||||||
|
private final Executor taskExecutor;
|
||||||
|
|
||||||
|
private final JobDetail[] jobDetails;
|
||||||
|
|
||||||
|
private final Map<String, Calendar> calendars;
|
||||||
|
|
||||||
|
private final Trigger[] triggers;
|
||||||
|
|
||||||
|
private final ApplicationContext applicationContext;
|
||||||
|
|
||||||
|
public QuartzAutoConfiguration(QuartzProperties properties,
|
||||||
|
ObjectProvider<List<SchedulerFactoryBeanCustomizer>> customizers,
|
||||||
|
ObjectProvider<Executor> taskExecutor, ObjectProvider<JobDetail[]> jobDetails,
|
||||||
|
ObjectProvider<Map<String, Calendar>> calendars,
|
||||||
|
ObjectProvider<Trigger[]> triggers,
|
||||||
|
ApplicationContext applicationContext) {
|
||||||
|
this.properties = properties;
|
||||||
|
this.customizers = customizers.getIfAvailable();
|
||||||
|
this.taskExecutor = taskExecutor.getIfAvailable();
|
||||||
|
this.jobDetails = jobDetails.getIfAvailable();
|
||||||
|
this.calendars = calendars.getIfAvailable();
|
||||||
|
this.triggers = triggers.getIfAvailable();
|
||||||
|
this.applicationContext = applicationContext;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
@ConditionalOnSingleCandidate(DataSource.class)
|
||||||
|
@ConditionalOnMissingBean
|
||||||
|
public QuartzDatabaseInitializer quartzDatabaseInitializer(DataSource dataSource,
|
||||||
|
ResourceLoader resourceLoader) {
|
||||||
|
return new QuartzDatabaseInitializer(dataSource, resourceLoader, this.properties);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
@ConditionalOnMissingBean
|
||||||
|
public SchedulerFactoryBean quartzScheduler() {
|
||||||
|
SchedulerFactoryBean schedulerFactoryBean = new SchedulerFactoryBean();
|
||||||
|
schedulerFactoryBean.setJobFactory(new AutowireCapableBeanJobFactory(
|
||||||
|
this.applicationContext.getAutowireCapableBeanFactory()));
|
||||||
|
if (!this.properties.getProperties().isEmpty()) {
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
if (this.calendars != null && !this.calendars.isEmpty()) {
|
||||||
|
schedulerFactoryBean.setCalendars(this.calendars);
|
||||||
|
}
|
||||||
|
if (this.triggers != null && this.triggers.length > 0) {
|
||||||
|
schedulerFactoryBean.setTriggers(this.triggers);
|
||||||
|
}
|
||||||
|
customize(schedulerFactoryBean);
|
||||||
|
return schedulerFactoryBean;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Properties asProperties(Map<String, String> source) {
|
||||||
|
Properties properties = new Properties();
|
||||||
|
properties.putAll(source);
|
||||||
|
return properties;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void customize(SchedulerFactoryBean schedulerFactoryBean) {
|
||||||
|
if (this.customizers != null) {
|
||||||
|
for (SchedulerFactoryBeanCustomizer customizer : this.customizers) {
|
||||||
|
customizer.customize(schedulerFactoryBean);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
@ConditionalOnSingleCandidate(DataSource.class)
|
||||||
|
protected static class JdbcStoreTypeConfiguration {
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public SchedulerFactoryBeanCustomizer dataSourceCustomizer(
|
||||||
|
QuartzProperties properties, DataSource dataSource,
|
||||||
|
ObjectProvider<PlatformTransactionManager> transactionManager) {
|
||||||
|
return schedulerFactoryBean -> {
|
||||||
|
if (properties.getJobStoreType() == JobStoreType.JDBC) {
|
||||||
|
schedulerFactoryBean.setDataSource(dataSource);
|
||||||
|
PlatformTransactionManager txManager =
|
||||||
|
transactionManager.getIfUnique();
|
||||||
|
if (txManager != null) {
|
||||||
|
schedulerFactoryBean.setTransactionManager(txManager);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,70 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2012-2017 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.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.springframework.boot.autoconfigure.quartz;
|
||||||
|
|
||||||
|
import javax.sql.DataSource;
|
||||||
|
|
||||||
|
import org.springframework.boot.autoconfigure.AbstractDatabaseInitializer;
|
||||||
|
import org.springframework.core.io.ResourceLoader;
|
||||||
|
import org.springframework.util.Assert;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializer for Quartz Scheduler schema.
|
||||||
|
*
|
||||||
|
* @author Vedran Pavic
|
||||||
|
* @since 2.0.0
|
||||||
|
*/
|
||||||
|
public class QuartzDatabaseInitializer extends AbstractDatabaseInitializer {
|
||||||
|
|
||||||
|
private final QuartzProperties properties;
|
||||||
|
|
||||||
|
public QuartzDatabaseInitializer(DataSource dataSource, ResourceLoader resourceLoader,
|
||||||
|
QuartzProperties properties) {
|
||||||
|
super(dataSource, resourceLoader);
|
||||||
|
Assert.notNull(properties, "QuartzProperties must not be null");
|
||||||
|
this.properties = properties;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean isEnabled() {
|
||||||
|
return this.properties.getJdbc().isInitializeSchema();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String getSchemaLocation() {
|
||||||
|
return this.properties.getJdbc().getSchema();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String getDatabaseName() {
|
||||||
|
String databaseName = super.getDatabaseName();
|
||||||
|
if ("db2".equals(databaseName)) {
|
||||||
|
return "db2_v95";
|
||||||
|
}
|
||||||
|
if ("mysql".equals(databaseName)) {
|
||||||
|
return "mysql_innodb";
|
||||||
|
}
|
||||||
|
if ("postgresql".equals(databaseName)) {
|
||||||
|
return "postgres";
|
||||||
|
}
|
||||||
|
if ("sqlserver".equals(databaseName)) {
|
||||||
|
return "sqlServer";
|
||||||
|
}
|
||||||
|
return databaseName;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,95 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2012-2017 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.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.springframework.boot.autoconfigure.quartz;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configuration properties for the Quartz Scheduler integration.
|
||||||
|
*
|
||||||
|
* @author Vedran Pavic
|
||||||
|
* @author Stephane Nicoll
|
||||||
|
* @since 2.0.0
|
||||||
|
*/
|
||||||
|
@ConfigurationProperties("spring.quartz")
|
||||||
|
public class QuartzProperties {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Quartz job store type.
|
||||||
|
*/
|
||||||
|
private JobStoreType jobStoreType = JobStoreType.MEMORY;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Additional Quartz Scheduler properties.
|
||||||
|
*/
|
||||||
|
private final Map<String, String> properties = new HashMap<>();
|
||||||
|
|
||||||
|
private final Jdbc jdbc = new Jdbc();
|
||||||
|
|
||||||
|
public JobStoreType getJobStoreType() {
|
||||||
|
return this.jobStoreType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setJobStoreType(JobStoreType jobStoreType) {
|
||||||
|
this.jobStoreType = jobStoreType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<String, String> getProperties() {
|
||||||
|
return this.properties;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Jdbc getJdbc() {
|
||||||
|
return this.jdbc;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Jdbc {
|
||||||
|
|
||||||
|
private static final String DEFAULT_SCHEMA_LOCATION = "classpath:org/quartz/impl/"
|
||||||
|
+ "jdbcjobstore/tables_@@platform@@.sql";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Path to the SQL file to use to initialize the database schema.
|
||||||
|
*/
|
||||||
|
private String schema = DEFAULT_SCHEMA_LOCATION;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create the required Quartz Scheduler tables on startup.
|
||||||
|
*/
|
||||||
|
private boolean initializeSchema;
|
||||||
|
|
||||||
|
public String getSchema() {
|
||||||
|
return this.schema;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSchema(String schema) {
|
||||||
|
this.schema = schema;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isInitializeSchema() {
|
||||||
|
return this.initializeSchema;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setInitializeSchema(boolean initializeSchema) {
|
||||||
|
this.initializeSchema = initializeSchema;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,37 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2012-2017 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.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.springframework.boot.autoconfigure.quartz;
|
||||||
|
|
||||||
|
import org.springframework.scheduling.quartz.SchedulerFactoryBean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Callback interface that can be implemented by beans wishing to customize the Quartz
|
||||||
|
* {@link SchedulerFactoryBean} before it is fully initialized, in particular to tune its
|
||||||
|
* configuration.
|
||||||
|
*
|
||||||
|
* @author Vedran Pavic
|
||||||
|
* @since 2.0.0
|
||||||
|
*/
|
||||||
|
public interface SchedulerFactoryBeanCustomizer {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Customize the {@link SchedulerFactoryBean}.
|
||||||
|
* @param schedulerFactoryBean the scheduler to customize
|
||||||
|
*/
|
||||||
|
void customize(SchedulerFactoryBean schedulerFactoryBean);
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,20 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2012-2017 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.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Auto-configuration for Quartz Scheduler.
|
||||||
|
*/
|
||||||
|
package org.springframework.boot.autoconfigure.quartz;
|
@ -0,0 +1,296 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2012-2017 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.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.springframework.boot.autoconfigure.quartz;
|
||||||
|
|
||||||
|
import java.util.concurrent.Executor;
|
||||||
|
import java.util.concurrent.Executors;
|
||||||
|
|
||||||
|
import javax.sql.DataSource;
|
||||||
|
|
||||||
|
import org.junit.After;
|
||||||
|
import org.junit.Rule;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.rules.ExpectedException;
|
||||||
|
import org.quartz.Calendar;
|
||||||
|
import org.quartz.JobBuilder;
|
||||||
|
import org.quartz.JobDetail;
|
||||||
|
import org.quartz.JobExecutionContext;
|
||||||
|
import org.quartz.JobExecutionException;
|
||||||
|
import org.quartz.JobKey;
|
||||||
|
import org.quartz.Scheduler;
|
||||||
|
import org.quartz.SchedulerException;
|
||||||
|
import org.quartz.SimpleScheduleBuilder;
|
||||||
|
import org.quartz.Trigger;
|
||||||
|
import org.quartz.TriggerBuilder;
|
||||||
|
import org.quartz.TriggerKey;
|
||||||
|
import org.quartz.impl.calendar.MonthlyCalendar;
|
||||||
|
import org.quartz.impl.calendar.WeeklyCalendar;
|
||||||
|
import org.quartz.simpl.RAMJobStore;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration;
|
||||||
|
import org.springframework.boot.autoconfigure.jdbc.EmbeddedDataSourceConfiguration;
|
||||||
|
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.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.ObjectUtils;
|
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
import static org.hamcrest.CoreMatchers.containsString;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests for {@link QuartzAutoConfiguration}.
|
||||||
|
*
|
||||||
|
* @author Vedran Pavic
|
||||||
|
* @author Stephane Nicoll
|
||||||
|
*/
|
||||||
|
public class QuartzAutoConfigurationTests {
|
||||||
|
|
||||||
|
@Rule
|
||||||
|
public final ExpectedException thrown = ExpectedException.none();
|
||||||
|
|
||||||
|
@Rule
|
||||||
|
public OutputCapture output = new OutputCapture();
|
||||||
|
|
||||||
|
private ConfigurableApplicationContext context;
|
||||||
|
|
||||||
|
@After
|
||||||
|
public void closeContext() {
|
||||||
|
if (this.context != null) {
|
||||||
|
this.context.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@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);
|
||||||
|
}
|
||||||
|
|
||||||
|
@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);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void withDataSource() throws Exception {
|
||||||
|
load(new Class<?>[] { QuartzJobsConfiguration.class,
|
||||||
|
EmbeddedDataSourceConfiguration.class,
|
||||||
|
DataSourceTransactionManagerAutoConfiguration.class },
|
||||||
|
"spring.quartz.job-store-type=jdbc",
|
||||||
|
"spring.quartz.jdbc.initialize-schema=true");
|
||||||
|
testWithDataSource();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void withDataSourceNoTransactionManager() throws Exception {
|
||||||
|
load(new Class<?>[] { QuartzJobsConfiguration.class,
|
||||||
|
EmbeddedDataSourceConfiguration.class },
|
||||||
|
"spring.quartz.job-store-type=jdbc",
|
||||||
|
"spring.quartz.jdbc.initialize-schema=true");
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
@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);
|
||||||
|
}
|
||||||
|
|
||||||
|
@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"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@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();
|
||||||
|
}
|
||||||
|
|
||||||
|
@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");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void withCustomizer() throws Exception {
|
||||||
|
load(QuartzCustomConfig.class);
|
||||||
|
assertThat(this.context.getBeansOfType(Scheduler.class)).hasSize(1);
|
||||||
|
Scheduler scheduler = this.context.getBean(Scheduler.class);
|
||||||
|
assertThat(scheduler.getSchedulerName()).isEqualTo("fooScheduler");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void load(String... environment) {
|
||||||
|
load(new Class<?>[0], environment);
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
protected static class QuartzJobsConfiguration {
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public JobDetail fooJob() {
|
||||||
|
return JobBuilder.newJob().ofType(FooJob.class).withIdentity("fooJob")
|
||||||
|
.storeDurably().build();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public JobDetail barJob() {
|
||||||
|
return JobBuilder.newJob().ofType(FooJob.class).withIdentity("barJob")
|
||||||
|
.storeDurably().build();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
protected static class QuartzFullConfiguration {
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public JobDetail fooJob() {
|
||||||
|
return JobBuilder.newJob().ofType(FooJob.class).withIdentity("fooJob")
|
||||||
|
.usingJobData("jobDataKey", "jobDataValue")
|
||||||
|
.storeDurably().build();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public Trigger fooTrigger() {
|
||||||
|
SimpleScheduleBuilder scheduleBuilder = SimpleScheduleBuilder.simpleSchedule()
|
||||||
|
.withIntervalInSeconds(10).repeatForever();
|
||||||
|
|
||||||
|
return TriggerBuilder.newTrigger().forJob(fooJob()).withIdentity("fooTrigger")
|
||||||
|
.withSchedule(scheduleBuilder).build();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
protected static class QuartzCalendarsConfiguration {
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public Calendar weekly() {
|
||||||
|
return new WeeklyCalendar();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public Calendar monthly() {
|
||||||
|
return new MonthlyCalendar();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
protected static class QuartzExecutorConfiguration {
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public Executor executor() {
|
||||||
|
return Executors.newSingleThreadExecutor();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
protected static class QuartzCustomConfig {
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public SchedulerFactoryBeanCustomizer customizer() {
|
||||||
|
return schedulerFactoryBean -> schedulerFactoryBean
|
||||||
|
.setSchedulerName("fooScheduler");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class FooJob extends QuartzJobBean {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private Environment env;
|
||||||
|
|
||||||
|
private String jobDataKey;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void executeInternal(JobExecutionContext context)
|
||||||
|
throws JobExecutionException {
|
||||||
|
System.out.println(this.env.getProperty("test-name", "unknown") + " - "
|
||||||
|
+ this.jobDataKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setJobDataKey(String jobDataKey) {
|
||||||
|
this.jobDataKey = jobDataKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,11 @@
|
|||||||
|
== Spring Boot Quartz Sample
|
||||||
|
|
||||||
|
This sample demonstrates the Quartz auto-configuration support.
|
||||||
|
|
||||||
|
The sample uses Maven. It can be built and run from the command line:
|
||||||
|
|
||||||
|
----
|
||||||
|
$ mvn spring-boot:run
|
||||||
|
----
|
||||||
|
|
||||||
|
Console log will now show "Hello World!" from `SampleJob` every 2 seconds.
|
@ -0,0 +1,35 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
<parent>
|
||||||
|
<!-- Your own application should inherit from spring-boot-starter-parent -->
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-samples</artifactId>
|
||||||
|
<version>2.0.0.BUILD-SNAPSHOT</version>
|
||||||
|
</parent>
|
||||||
|
<artifactId>spring-boot-sample-quartz</artifactId>
|
||||||
|
<name>Spring Boot Quartz Sample</name>
|
||||||
|
<description>Spring Boot Quartz Sample</description>
|
||||||
|
<url>http://projects.spring.io/spring-boot/</url>
|
||||||
|
<organization>
|
||||||
|
<name>Pivotal Software, Inc.</name>
|
||||||
|
<url>http://www.spring.io</url>
|
||||||
|
</organization>
|
||||||
|
<properties>
|
||||||
|
<main.basedir>${basedir}/../..</main.basedir>
|
||||||
|
</properties>
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-quartz</artifactId>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
</project>
|
@ -0,0 +1,39 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2012-2017 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.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package sample.quartz;
|
||||||
|
|
||||||
|
import org.quartz.JobExecutionContext;
|
||||||
|
import org.quartz.JobExecutionException;
|
||||||
|
|
||||||
|
import org.springframework.scheduling.quartz.QuartzJobBean;
|
||||||
|
|
||||||
|
public class SampleJob extends QuartzJobBean {
|
||||||
|
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
// Invoked if a Job data map entry with that name
|
||||||
|
public void setName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void executeInternal(JobExecutionContext context)
|
||||||
|
throws JobExecutionException {
|
||||||
|
System.out.println(String.format("Hello %s!", this.name));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,52 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2012-2017 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.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package sample.quartz;
|
||||||
|
|
||||||
|
import org.quartz.JobBuilder;
|
||||||
|
import org.quartz.JobDetail;
|
||||||
|
import org.quartz.SimpleScheduleBuilder;
|
||||||
|
import org.quartz.Trigger;
|
||||||
|
import org.quartz.TriggerBuilder;
|
||||||
|
|
||||||
|
import org.springframework.boot.SpringApplication;
|
||||||
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
|
||||||
|
@SpringBootApplication
|
||||||
|
public class SampleQuartzApplication {
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
SpringApplication.run(SampleQuartzApplication.class, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public JobDetail sampleJobDetail() {
|
||||||
|
return JobBuilder.newJob().ofType(SampleJob.class).withIdentity("sampleJob")
|
||||||
|
.usingJobData("name", "World")
|
||||||
|
.storeDurably().build();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public Trigger sampleJobTrigger() {
|
||||||
|
SimpleScheduleBuilder scheduleBuilder = SimpleScheduleBuilder.simpleSchedule()
|
||||||
|
.withIntervalInSeconds(2).repeatForever();
|
||||||
|
|
||||||
|
return TriggerBuilder.newTrigger().forJob(sampleJobDetail())
|
||||||
|
.withIdentity("sampleTrigger").withSchedule(scheduleBuilder).build();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,38 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
<parent>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starters</artifactId>
|
||||||
|
<version>2.0.0.BUILD-SNAPSHOT</version>
|
||||||
|
</parent>
|
||||||
|
<artifactId>spring-boot-starter-quartz</artifactId>
|
||||||
|
<name>Spring Boot Quartz Starter</name>
|
||||||
|
<description>Spring Boot Quartz Starter</description>
|
||||||
|
<url>http://projects.spring.io/spring-boot/</url>
|
||||||
|
<organization>
|
||||||
|
<name>Pivotal Software, Inc.</name>
|
||||||
|
<url>http://www.spring.io</url>
|
||||||
|
</organization>
|
||||||
|
<properties>
|
||||||
|
<main.basedir>${basedir}/../..</main.basedir>
|
||||||
|
</properties>
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework</groupId>
|
||||||
|
<artifactId>spring-context-support</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework</groupId>
|
||||||
|
<artifactId>spring-tx</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.quartz-scheduler</groupId>
|
||||||
|
<artifactId>quartz</artifactId>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
</project>
|
@ -0,0 +1 @@
|
|||||||
|
provides: spring-context-support,spring-tx,quartz
|
Loading…
Reference in New Issue