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,註解配置啓動及其集羣設置完畢。

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