Springboot集成quartz集群及其注解配置

之前需要老quartz(1.8.6)版本,集成到springboot(1.5.9)中,在网上查了许多资料,发现了几个问题:

  1. 全注解配置的较少,有的文章要求写入springboot的继承了ApplicationRunner类的run方法中才可以启动定时任务,感觉很别扭。
  2. 很多文章把spring的Schedule和quartz搞混了,声称必须加入@EnableScheduling注释才能启动quartz,其实那是spring的Schedule注解配置。
  3. 人云亦云引入无关的依赖(比如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,注解配置启动及其集群设置完毕。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章