构建Mysql表:SQL脚本
属性文件参考:quartz.properties
该项目是基于SpringBoot环境搭建,请搭建之前可以将SQL脚本先在数据库中进行执行。
属性文件可以先去了解。
注意我这里的版本是SpringBoot版本:2.1.0.RELEASE
SpringBoot中QuartzAutoConfiguration-QuartzProperties会读取配置环境中的以spring.quartz开头的配置并以此构建Quartz上下文。
spring: quartz: #相关属性配置 properties: org: quartz: scheduler: instanceName: clusteredScheduler instanceId: AUTO jobStore: class: org.quartz.impl.jdbcjobstore.JobStoreTX driverDelegateClass: org.quartz.impl.jdbcjobstore.StdJDBCDelegate tablePrefix: QRTZ_ isClustered: true clusterCheckinInterval: 10000 useProperties: false threadPool: class: org.quartz.simpl.SimpleThreadPool threadCount: 10 threadPriority: 5 threadsInheritContextClassLoaderOfInitializingThread: true这里需要注意的是SpringBoot的自动化配置类:QuartzAutoConfiguration 中已经默认将Quartz的默认配置配好,而你只需要将项目中特定的参数加进去,而SchedulerFactoryBeanCustomizer就是为了给用户自己配置自己需要的参数而设定的。
/** * Job调度配置 * * @author : liukx * @time : 2019/5/21 - 9:44 */ @Configuration public class JobConfig implements SchedulerFactoryBeanCustomizer { @Override public void customize(SchedulerFactoryBean schedulerFactoryBean) { // 让执行的job拥有上下文的环境 schedulerFactoryBean.setApplicationContextSchedulerContextKey("applicationContext"); } }实现
import com.elab.crawler.web.job.DefaultQuartzJobBean; import com.elab.crawler.web.services.IQuartzService; import com.elab.crawler.web.utils.JobUtils; import org.quartz.Scheduler; import org.quartz.SchedulerException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.stereotype.Service; import javax.annotation.PostConstruct; import java.util.Date; /** * 调度任务实现类 * * @author : liukx * @date : 2019/5/21 - 16:29 */ @Service("quartzServiceImpl") public class QuartzServiceImpl implements IQuartzService { private Logger logger = LoggerFactory.getLogger(QuartzServiceImpl.class); @Qualifier("Scheduler") @Autowired private Scheduler scheduler; @PostConstruct public void startScheduler() { try { scheduler.start(); logger.info(" 调度器启动了 ..."); } catch (SchedulerException e) { e.printStackTrace(); } } @Override public void addJob(String jobName, String jobGroupName, int jobTime, int runCount) throws Exception { logger.info(" 新增一个任务 jobName=" + jobName + ",jobGroupName" + jobGroupName + ",jobTime=" + jobTime + "," + "runCount=" + runCount); Date date = JobUtils.addJob(scheduler, DefaultQuartzJobBean.class, jobName, jobGroupName, jobTime, runCount); logger.info(" job任务 jobName=" + jobName + ",jobGroupName" + jobGroupName + " 执行完成 . " + date); } @Override public void addJob(String jobName, String jobGroupName, String jobTime) throws Exception { logger.info(" 新增一个任务 jobName=" + jobName + ",jobGroupName" + jobGroupName + ",jobTime=" + jobTime); Date date = JobUtils.addJob(scheduler, DefaultQuartzJobBean.class, jobName, jobGroupName, jobTime); logger.info(" job任务 jobName=" + jobName + ",jobGroupName" + jobGroupName + " 执行完成 . " + date); } /** * 修改 一个job的 时间表达式 * * @param jobName * @param jobGroupName * @param jobTime */ @Override public void updateJob(String jobName, String jobGroupName, String jobTime) throws Exception { logger.info(" 修改一个任务 jobName=" + jobName + ",jobGroupName" + jobGroupName + ",jobTime=" + jobTime); Date date = JobUtils.updateJob(scheduler, jobName, jobGroupName, jobTime); logger.info(" job任务 jobName=" + jobName + ",jobGroupName" + jobGroupName + " 执行完成 . "); } /** * 删除任务一个job * * @param jobName 任务名称 * @param jobGroupName 任务组名 */ @Override public void deleteJob(String jobName, String jobGroupName) throws Exception { logger.info(" 删除一个任务 jobName=" + jobName + ",jobGroupName" + jobGroupName + ",jobTime="); boolean result = JobUtils.deleteJob(scheduler, jobName, jobGroupName); logger.info(" job任务 jobName=" + jobName + ",jobGroupName" + jobGroupName + " 执行完成." + result); } /** * 暂停一个job * * @param jobName * @param jobGroupName */ @Override public void pauseJob(String jobName, String jobGroupName) throws Exception { logger.info(" 暂停一个任务 jobName=" + jobName + ",jobGroupName" + jobGroupName + ",jobTime="); JobUtils.pauseJob(scheduler, jobName, jobGroupName); logger.info(" job任务 jobName=" + jobName + ",jobGroupName" + jobGroupName + " 执行完成."); } /** * 恢复一个job * * @param jobName * @param jobGroupName */ @Override public void resumeJob(String jobName, String jobGroupName) throws Exception { logger.info(" 恢复一个任务 jobName=" + jobName + ",jobGroupName" + jobGroupName + ",jobTime="); JobUtils.resumeJob(scheduler, jobName, jobGroupName); logger.info(" 恢复一个任务 jobName=" + jobName + ",jobGroupName" + jobGroupName + "执行完成"); } /** * 立即执行一个job * * @param jobName * @param jobGroupName */ @Override public void runAJobNow(String jobName, String jobGroupName) throws Exception { logger.info(" 立即执行一个任务 jobName=" + jobName + ",jobGroupName" + jobGroupName + ",jobTime="); JobUtils.runAJobNow(scheduler, jobName, jobGroupName); logger.info(" 立即执行一个任务 jobName=" + jobName + ",jobGroupName" + jobGroupName + "完成 ..."); } }这里是调度的时候被触发的执行类。
import org.quartz.JobExecutionContext; import org.quartz.JobExecutionException; import org.quartz.TriggerKey; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.scheduling.quartz.QuartzJobBean; /** * 默认的Job执行器 * * @author : liukx * @time : 2019/5/21 - 16:32 */ public class DefaultQuartzJobBean extends QuartzJobBean { private Logger logger = LoggerFactory.getLogger(DefaultQuartzJobBean.class); @Override protected void executeInternal(JobExecutionContext jobExecutionContext) throws JobExecutionException { // 拿到Spring的上下文,可以自由的做业务处理 ApplicationContext applicationContext = (ApplicationContext) jobExecutionContext.getScheduler().getContext().get("applicationContext"); TriggerKey key = jobExecutionContext.getTrigger().getKey(); String group = key.getGroup(); String name = key.getName(); // 业务处理 ... logger.info(" 执行中 ... " + group + "\t" + name); } }StdSchedulerFactory:
通过instantiate方法开始实例化调度器 构建一个QuartzScheduler调度器,这个调度器是一个线程,负责拉取需要触发的TriggerQuartzSchedulerThread:
run 拉取即将执行的触发内容执行触发任务JobStoreSupport :
获取马上要fire的trigger列表将trigger的状态有WAITING更新为ACQUARIED将这个trigger信息insert进fired_triggers主流程
轮训拉取待触发的trigger。根据状态触发trigger。包装trigger,丢给工作线程。工作线程负责执行具体的任务原理参考