之前需要老quartz(1.8.6)版本,集成到springboot(1.5.9)中,在網上查了許多資料,發現了幾個問題:
- 全註解配置的較少,有的文章要求寫入springboot的繼承了ApplicationRunner類的run方法中纔可以啓動定時任務,感覺很彆扭。
- 很多文章把spring的Schedule和quartz搞混了,聲稱必須加入@EnableScheduling註釋才能啓動quartz,其實那是spring的Schedule註解配置。
- 人云亦云引入無關的依賴(比如spring-context-support)
進入正文,要項目用到的依賴加入pom.xml文件
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz</artifactId>
<version>2.2.3</version>
</dependency>
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz-jobs</artifactId>
<version>2.2.3</version>
</dependency>
進入Quartz官網,下載相應的Quartz 2.2.3.tar.gz包,解壓包找到對應數據庫的sql文件,初始化數據庫(我的是mysql)。
爲了能在Quartz新建的job中能實現spring的自動注入,需要用到SpringBeanJobFactory類
/**
* Autowire Quartz Jobs with Spring context dependencies
*/
@Component
public final class AutowiringSpringBeanJobFactory extends SpringBeanJobFactory
implements ApplicationContextAware {
private transient AutowireCapableBeanFactory beanFactory;
@Override
public void setApplicationContext(final ApplicationContext context) {
beanFactory = context.getAutowireCapableBeanFactory();
}
@Override
protected Object createJobInstance(final TriggerFiredBundle bundle)
throws Exception {
final Object job = super.createJobInstance(bundle);
beanFactory.autowireBean(job);
return job;
}
}
編寫job
@Component
public class SendEventsSchedule extends QuartzJobBean {
Logger log = Logger.getLogger(SendEventsSchedule.class.getName());
@Autowired
ServicesRepository servicesRepository;
public SendEventsSchedule(){
}
@Override
protected void executeInternal(JobExecutionContext context) throws JobExecutionException {
log.info("execute schedule begin");
try {
/*
* 這裏舉了個例子:servicesRepository是被spring自動注入了,
* 如果不寫AutowiringSpringBeanJobFactory類,
* 則servicesRepository就算用了@Autowired,但對象仍爲空。
*/
List<PushEvents> list = servicesRepository.findAllToSentEventsByPage(1, 20);
if(list != null && !list.isEmpty()) {
for(PushEvents event:list){
// todo something
}
}
} catch (Exception e) {
log.warning("execute schedule error:" + e.getMessage());
}
log.info("execute schedule end");
}
}
編寫Quartz的配置類
package com.itsnow.management.config;
import com.itsnow.management.web.schedule.AutowiringSpringBeanJobFactory;
import com.itsnow.management.web.schedule.SendEventsSchedule;
import org.quartz.JobDetail;
import org.quartz.Trigger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.scheduling.quartz.CronTriggerFactoryBean;
import org.springframework.scheduling.quartz.JobDetailFactoryBean;
import org.springframework.scheduling.quartz.SchedulerFactoryBean;
import java.util.logging.Logger;
@Configuration
public class QuartzConfig {
private Logger logger = Logger.getLogger(QuartzConfig.class.getName());
@Autowired
private AutowiringSpringBeanJobFactory autowiringSpringBeanJobFactory;
// 配置文件路徑,別忘了加上根路徑
private static final String QUARTZ_CONFIG = "/quartz.properties";
@Bean
public JobDetailFactoryBean jobDetail() {
JobDetailFactoryBean bean = new JobDetailFactoryBean();
bean.setJobClass(SendEventsSchedule.class);
// 給jobs添加trigger觸發器,不加這句話,我這裏第二次啓動時會報錯(未添加觸發器)
bean.setDurability(true);
return bean;
}
// 配置觸發器,這裏觸發器使用的是cronTrigger,沒有使用simpleTrigger,
@Bean
public CronTriggerFactoryBean cornTriggerFactoryBean(JobDetail jobDetail) {
CronTriggerFactoryBean bean = new CronTriggerFactoryBean();
bean.setCronExpression("0 0/2 * * * ?");//每兩分鐘一次
bean.setJobDetail(jobDetail);
return bean;
}
/**
* 配置定時任務自動觸發
* @param trigger
* @param dataSourceTransactionManager spring容器自帶的數據源管理器
* @return
*/
@Bean
public SchedulerFactoryBean schedulerFactoryBean(Trigger trigger,
DataSourceTransactionManager dataSourceTransactionManager) {
SchedulerFactoryBean bean = new SchedulerFactoryBean();
bean.setOverwriteExistingJobs(true);
bean.setDataSource(dataSourceTransactionManager.getDataSource());
bean.setJobFactory(autowiringSpringBeanJobFactory);
bean.setConfigLocation(new ClassPathResource(QUARTZ_CONFIG));
bean.setTriggers(trigger);
return bean;
}
}
Quartz配置文件quartz.properties內容
# Using Spring datasource in quartzJobsConfig.xml
# Spring uses LocalDataSourceJobStore extension of JobStoreCMT
# 此屬性表示是否以字符串形式存儲,我這裏用true報錯,所以改爲了false,用對象存儲。
org.quartz.jobStore.useProperties=false
org.quartz.jobStore.tablePrefix=QRTZ_
org.quartz.jobStore.isClustered=true
# 10 mins
org.quartz.jobStore.clusterCheckinInterval=600000
org.quartz.scheduler.skipUpdateCheck=true
# Change this to match your DB vendor
org.quartz.jobStore.driverDelegateClass=org.quartz.impl.jdbcjobstore.StdJDBCDelegate
# Needed to manage cluster instances
org.quartz.scheduler.instanceId=AUTO
org.quartz.scheduler.instanceName=MY_JOB_SCHEDULER
org.quartz.scheduler.rmi.export=false
org.quartz.scheduler.rmi.proxy=false
org.quartz.threadPool.class=org.quartz.simpl.SimpleThreadPool
org.quartz.threadPool.threadCount=10
org.quartz.threadPool.threadPriority=5
org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread=true
至此在springboot中集成Quartz,註解配置啓動及其集羣設置完畢。