兩者區別與作用:
普通任務:總調度(SchedulerFactoryBean)--> 定時調度器(CronTriggerFactoryBean) --> 調度明細自定義執行方法bean(MethodInvokingJobDetailFactoryBean) -->調度bean(我們定義的job類)
可傳參任務:總調度(SchedulerFactoryBean)--> 定時調度器(CronTriggerFactoryBean) --> 調度明細bean(JobDetailFactoryBean)
如上是我們在配置調度器時的具體步驟及相互之間的依賴,區別主要在調度明細bean上,普通任務是(MethodInvokingJobDetailFactoryBean),而可傳參任務是(JobDetailFactoryBean):
1)普通任務可以自定義執行方法,也就是說在其配置的調度bean(我們定義的job類)中我們可以自定義調度器最終執行的方法,可以叫work1也可以叫work2,and so on。而且要記住的一點,必須是無入參的方法!!!(做了一個測試,測試目的是看通過此類型調度類型是否也能傳入參數所以定義了一個帶入參的自定義方法即public void work(JobExecutionContext jobExecutionContext),最中測試結果是spring quartz會報找不到work方法及No such method work(),其默認執行我們生命的work無入參的方法。
2)可傳參任務必須繼承QuartzJobBean,重寫protected void executeInternal(JobExecutionContext jobExecutionContext) throws JobExecutionException方法,其中JobExecutionContext就是我們在定義調度器明細時傳入參數的上下文,我們可以通過JobExecutionContext取出傳入的map,調度任務最終執行的就是executeInternal方法,使用該調度明細任務無法使用自定義方法。
提供三種形式的定時任務:
1、固定等待時間 @Scheduled(fixedDelay = 時間間隔 )
2、固定間隔時間 @Scheduled(fixedRate = 時間間隔 )
3、Corn表達式 @Scheduled(cron = Corn表達式)
添加依賴(不知道為什么要加jboss-logging依賴,沒有會報錯)

<!-- 添加springboot對Quartz的支持 --> <dependency> <groupId>org.quartz-scheduler</groupId> <artifactId>quartz</artifactId> <version>2.3.0</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context-support</artifactId> </dependency> <!-- https://mvnrepository.com/artifact/org.jboss.logging/jboss-logging --> <dependency> <groupId>org.jboss.logging</groupId> <artifactId>jboss-logging</artifactId> </dependency>
配置quartz.properties

#===============================================================
#Configure Main Scheduler Properties 調度器屬性
#===============================================================
#調度器的實例名
org.quartz.scheduler.instanceName = QuartzScheduler
#調度器的實例ID,大多數情況設置為auto即可
org.quartz.scheduler.instanceId = AUTO
#===============================================================
#Configure ThreadPool 線程池屬性
#===============================================================
#處理Job的線程個數,至少為1,但最多的話最好不要超過100,在多數機器上設置該值超過100的話就會顯得相當不實用了,特別是在你的 Job 執行時間較長的情況下
org.quartz.threadPool.threadCount = 5
#線程的優先級,優先級別高的線程比級別低的線程優先得到執行。最小為1,最大為10,默認為5
org.quartz.threadPool.threadPriority = 5
#一個實現了 org.quartz.spi.ThreadPool 接口的類,Quartz 自帶的線程池實現類是 org.quartz.smpl.SimpleThreadPool
org.quartz.threadPool.class = org.quartz.simpl.SimpleThreadPool
#===============================================================
#Configure JobStore 作業存儲設置
#===============================================================
#要使 Job 存儲在內存中需通過設置 org.quartz.jobStrore.class 屬性為 org.quartz.simpl.RAMJobStore
org.quartz.jobStore.class = org.quartz.simpl.RAMJobStore
一、普通任務
1、任務類

package cloud.app.prod.home.quartz.mem; import org.apache.log4j.Logger; import org.springframework.context.annotation.Configuration; import org.springframework.scheduling.annotation.EnableScheduling; import org.springframework.stereotype.Component; import cloud.app.prod.home.common.FailException; /** * Author : YongBo Xie </br> * File Name: ScheduleTask.java </br> * Created Date: 2018年3月31日 下午3:37:43 </br> * Modified Date: 2018年3月31日 下午3:37:43 </br> * Version: 1.0 </br> */ @Configuration @Component // 此注解必加 @EnableScheduling // 此注解必加 public class ScheduleTask { private static Logger logger = Logger.getLogger(ScheduleTask.class); public void marketingActivity() throws FailException { logger.info("execute activity"); } }
2、Quartz配置類

package cloud.app.prod.home.quartz.mem; import org.quartz.Trigger; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.scheduling.quartz.CronTriggerFactoryBean; import org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean; import org.springframework.scheduling.quartz.SchedulerFactoryBean; /** * Author : YongBo Xie </br> * File Name: QuartzConfigration.java </br> * Created Date: 2018年3月31日 下午3:42:04 </br> * Modified Date: 2018年3月31日 下午3:42:04 </br> * Version: 1.0 </br> */ @Configuration public class QuartzConfigration { /** * Details:配置定時任務 */ @Bean(name = "marketingActivityJobDetail") public MethodInvokingJobDetailFactoryBean detailFactoryBean(ScheduleTask task) {// ScheduleTask為需要執行的任務 MethodInvokingJobDetailFactoryBean jobDetail = new MethodInvokingJobDetailFactoryBean(); /* * 是否並發執行 * 例如每5s執行一次任務,但是當前任務還沒有執行完,就已經過了5s了, * 如果此處為true,則下一個任務會執行,如果此處為false,則下一個任務會等待上一個任務執行完后,再開始執行 */ jobDetail.setConcurrent(false); jobDetail.setName("marketing_activity");// 設置任務的名字 jobDetail.setGroup("marketing_activity");// 設置任務的分組,這些屬性都可以存儲在數據庫中,在多任務的時候使用 /* * 為需要執行的實體類對應的對象 */ jobDetail.setTargetObject(task); /* * marketingActivity為需要執行的方法 * 通過這幾個配置,告訴JobDetailFactoryBean我們需要執行定時執行ScheduleTask類中的marketingActivity方法 */ jobDetail.setTargetMethod("marketingActivity"); return jobDetail; } /** * Details:配置定時任務的觸發器,也就是什么時候觸發執行定時任務 */ @Bean(name = "marketingActivityJobTrigger") public CronTriggerFactoryBean cronJobTrigger(MethodInvokingJobDetailFactoryBean jobDetail) { CronTriggerFactoryBean tigger = new CronTriggerFactoryBean(); tigger.setJobDetail(jobDetail.getObject()); tigger.setCronExpression("0 0 1 * * ?");// 初始時的cron表達式 ,每天1點執行 tigger.setName("marketing_activity");// trigger的name return tigger; } /** * Details:定義quartz調度工廠 */ @Bean(name = "marketingActivityScheduler") public SchedulerFactoryBean schedulerFactory(Trigger cronJobTrigger) { SchedulerFactoryBean bean = new SchedulerFactoryBean(); // 用於quartz集群,QuartzScheduler 啟動時更新己存在的Job bean.setOverwriteExistingJobs(true); // 延時啟動,應用啟動1秒后 bean.setStartupDelay(1); // 注冊觸發器 bean.setTriggers(cronJobTrigger); return bean; } }
3、定時查庫,並更新任務

package cloud.app.prod.home.quartz.mem; import javax.annotation.Resource; import org.quartz.CronScheduleBuilder; import org.quartz.CronTrigger; import org.quartz.JobDetail; import org.quartz.Scheduler; import org.quartz.SchedulerException; import org.springframework.context.annotation.Configuration; import org.springframework.scheduling.annotation.EnableScheduling; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Component; import cloud.app.prod.home.common.FailException; import cloud.app.prod.home.mem.vo.MarketingActivitiesVO; import cloud.app.prod.home.utils.DSHUtils; /** * Author : YongBo Xie </br> * File Name: ScheduleRefreshDatabase.java </br> * Created Date: 2018年3月31日 下午3:58:08 </br> * Modified Date: 2018年3月31日 下午3:58:08 </br> * Version: 1.0 </br> */ @Configuration @EnableScheduling @Component public class ScheduleRefreshCron { @Resource(name = "marketingActivityJobDetail") private JobDetail jobDetail; @Resource(name = "marketingActivityJobTrigger") private CronTrigger cronTrigger; @Resource(name = "marketingActivityScheduler") private Scheduler scheduler; @Scheduled(fixedRate = 5000) // 每隔5s查庫,並根據查詢結果決定是否重新設置定時任務 // @Scheduled(cron = "0 0 1 * * ?") public void scheduleUpdateCronTrigger() throws SchedulerException, FailException { CronTrigger trigger = (CronTrigger) scheduler.getTrigger(cronTrigger.getKey()); String currentCron = trigger.getCronExpression();// 當前Trigger使用的 String searchCron = "0 41 10 ? * *";// 從數據庫查詢出來的 System.out.println(currentCron); System.out.println(searchCron); // 如果當前使用的cron表達式和從數據庫中查詢出來的cron表達式一致,則不刷新任務 if (!currentCron.equals(searchCron)) { MarketingActivitiesVO marketingActivitiesVO = new MarketingActivitiesVO(); marketingActivitiesVO.setId(DSHUtils.generateUUID()); // 表達式調度構建器 CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(searchCron); // 按新的cronExpression表達式重新構建trigger trigger = (CronTrigger) scheduler.getTrigger(cronTrigger.getKey()); trigger = trigger.getTriggerBuilder().withIdentity(cronTrigger.getKey()) .withSchedule(scheduleBuilder).build(); // 按新的trigger重新設置job執行 scheduler.rescheduleJob(cronTrigger.getKey(), trigger); currentCron = searchCron; } } }
二、可傳參任務
在Spring Boot中使用Quartz時,如果job涉及到調用其他自定義方法,需要通過定義Job Factory實現自動注入
傳參關鍵代碼:
1)、接收參數

@Override protected void executeInternal(JobExecutionContext context) throws JobExecutionException { JobDataMap dataMap = context.getJobDetail().getJobDataMap(); MarketingActivitiesVO marketingActivitiesVO = (MarketingActivitiesVO) dataMap.get("marketingActivitiesVO"); }
2)、傳入參數

// 創建一項作業 JobDetail job = JobBuilder.newJob(ScheduleTask.class) .withIdentity("marketingActivityJob", "marketingActivityGroup") .build(); // 設置參數 MarketingActivitiesVO marketingActivitiesVO = new MarketingActivitiesVO(); marketingActivitiesVO.setId(DSHUtils.generateUUID()); job.getJobDataMap().put("marketingActivitiesVO", marketingActivitiesVO);
1、自定義MyJobFactory類

package cloud.app.prod.home.quartz; import org.quartz.spi.TriggerFiredBundle; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.config.AutowireCapableBeanFactory; import org.springframework.scheduling.quartz.AdaptableJobFactory; import org.springframework.stereotype.Component; /** * Author : YongBo Xie </br> * File Name: MyJobFactory.java </br> * Created Date: 2018年4月2日 下午3:27:30 </br> * Modified Date: 2018年4月2日 下午3:27:30 </br> * Version: 1.0 </br> */ @Component public class MyJobFactory extends AdaptableJobFactory { @Autowired private AutowireCapableBeanFactory capableBeanFactory; @Override protected Object createJobInstance(TriggerFiredBundle bundle) throws Exception { // 調用父類的方法 Object jobInstance = super.createJobInstance(bundle); // 進行注入 capableBeanFactory.autowireBean(jobInstance); return jobInstance; } }
2、配置SchedulerFactoryBean

package cloud.app.prod.home.quartz; import java.io.IOException; import java.util.Properties; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.config.PropertiesFactoryBean; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.core.io.ClassPathResource; import org.springframework.scheduling.annotation.EnableScheduling; import org.springframework.scheduling.quartz.SchedulerFactoryBean; import cloud.app.prod.home.quartz.MyJobFactory; /** * Author : YongBo Xie </br> * File Name: QuartzConfigration.java </br> * Created Date: 2018年3月31日 下午3:42:04 </br> * Modified Date: 2018年3月31日 下午3:42:04 </br> * Version: 1.0 </br> */ @Configuration @EnableScheduling public class QuartzConfigration { @Autowired private MyJobFactory myJobFactory; @Bean public SchedulerFactoryBean schedulerFactoryBean() throws IOException { SchedulerFactoryBean factory = new SchedulerFactoryBean(); // 用於quartz集群,QuartzScheduler 啟動時更新己存在的Job factory.setOverwriteExistingJobs(true); // 延時啟動,應用啟動1秒后 // factory.setStartupDelay(1); // 加載quartz數據源配置 // factory.setQuartzProperties(quartzProperties()); // 自定義Job Factory,用於Spring注入 factory.setJobFactory(myJobFactory); return factory; } /** * 加載quartz數據源配置 * * @return * @throws IOException */ @Bean public Properties quartzProperties() throws IOException { PropertiesFactoryBean propertiesFactoryBean = new PropertiesFactoryBean(); propertiesFactoryBean.setLocation(new ClassPathResource("/quartz.properties")); propertiesFactoryBean.afterPropertiesSet(); return propertiesFactoryBean.getObject(); } }
3、執行任務類

package cloud.app.prod.home.quartz.mem; import org.apache.log4j.Logger; import org.quartz.DisallowConcurrentExecution; import org.quartz.JobDataMap; import org.quartz.JobExecutionContext; import org.quartz.JobExecutionException; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Configuration; import org.springframework.scheduling.annotation.EnableScheduling; import org.springframework.scheduling.quartz.QuartzJobBean; import org.springframework.stereotype.Component; import cloud.app.prod.home.common.FailException; import cloud.app.prod.home.mem.vo.MarketingActivitiesVO; import cloud.app.prod.home.rabbitmq.mem.MarketingActivitieRabbitMqSender; /** * Author : YongBo Xie </br> * File Name: ScheduleTask.java </br> * Created Date: 2018年3月31日 下午3:37:43 </br> * Modified Date: 2018年3月31日 下午3:37:43 </br> * Version: 1.0 </br> */ @Configuration @Component // 此注解必加 @EnableScheduling // 此注解必加 @DisallowConcurrentExecution // 任務同步 public class ScheduleTask extends QuartzJobBean { private static Logger logger = Logger.getLogger(ScheduleTask.class); @Autowired private MarketingActivitieRabbitMqSender marketingActivitieRabbitMqSender; @Override protected void executeInternal(JobExecutionContext context) throws JobExecutionException { logger.info("execute activity"); JobDataMap dataMap = context.getJobDetail().getJobDataMap(); MarketingActivitiesVO marketingActivitiesVO = (MarketingActivitiesVO) dataMap.get("marketingActivitiesVO"); logger.info("marketingActivitiesVO.id: " + marketingActivitiesVO.getId()); try { logger.info("marketingActivitieRabbitMqSender: " + marketingActivitieRabbitMqSender); marketingActivitieRabbitMqSender.sendRabbitmqDirect(marketingActivitiesVO); } catch (FailException e) { e.printStackTrace(); } } }
4、設置任務類

package cloud.app.prod.home.quartz.mem; import java.util.Date; import org.apache.log4j.Logger; import org.quartz.CronScheduleBuilder; import org.quartz.CronTrigger; import org.quartz.DateBuilder; import org.quartz.JobBuilder; import org.quartz.JobDetail; import org.quartz.Scheduler; import org.quartz.SchedulerException; import org.quartz.TriggerBuilder; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Configuration; import org.springframework.scheduling.annotation.EnableScheduling; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.scheduling.quartz.SchedulerFactoryBean; import org.springframework.stereotype.Component; import cloud.app.prod.home.common.FailException; import cloud.app.prod.home.mem.vo.MarketingActivitiesVO; import cloud.app.prod.home.utils.DSHUtils; /** * Author : YongBo Xie </br> * Project Name: DSH-SCRM </br> * Created Date: 2018年3月31日 下午3:58:08 </br> * Modified Date: 2018年3月31日 下午3:58:08 </br> * Version: 1.0 </br> */ @Configuration @EnableScheduling @Component public class ScheduleRefreshCron { private static Logger logger = Logger.getLogger(ScheduleRefreshCron.class); @Autowired private SchedulerFactoryBean schedulerFactoryBean; @Scheduled(fixedRate = 5000) // 每隔5s查庫 // @Scheduled(cron = "0 0 1 * * ?") public void scheduleUpdateCronTrigger() throws FailException, SchedulerException { try{ logger.info("----- scheduling job --------"); String searchCron = "*/5 * * * * ?";// 從數據庫查詢出來的 // 獲取一個調度器 // SchedulerFactory factory = new StdSchedulerFactory(); // Scheduler scheduler = factory.getScheduler(); Scheduler scheduler = schedulerFactoryBean.getScheduler(); // 創建一項作業 JobDetail job = JobBuilder.newJob(ScheduleTask.class) .withIdentity("marketingActivityJob", "marketingActivityGroup") .build(); // 設置參數 MarketingActivitiesVO marketingActivitiesVO = new MarketingActivitiesVO(); marketingActivitiesVO.setId(DSHUtils.generateUUID()); job.getJobDataMap().put("marketingActivitiesVO", marketingActivitiesVO); // 作業的執行時間(當前時間的下一分鍾) Date runTime = DateBuilder.evenMinuteDate(new Date()); // 創建一個觸發器 CronTrigger trigger = (CronTrigger)TriggerBuilder.newTrigger() .withIdentity("marketingActivityTrigger", "marketingActivityGroup") .startAt(runTime) //該觸發器將在runTime時執行作業 .endAt(new Date(System.currentTimeMillis()+5*1000+60*1000)) //該觸發器將在runTime時結束作業 .withSchedule(CronScheduleBuilder.cronSchedule(searchCron)) // 具體執行時間 .build(); // 告訴調度器使用該觸發器來安排作業 scheduler.scheduleJob(job, trigger); // 啟動調度器 scheduler.start(); logger.info("------ started scheduler -------"); logger.info("------ waiting 2 minutes ------"); Thread.sleep(2*60*1000); logger.info("------- shutting down ------"); // 關閉調度器 scheduler.shutdown(true); logger.info("------- shutdown complete -------"); }catch(Exception e){ logger.error(DSHUtils.formatException(e)); throw new FailException(e.getMessage()); } } }