之前需要老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,注解配置启动及其集群设置完毕。