Spring Boot集成Quartz定时任务详解

在实际项目开发中,我们想在规定时间执行一些任务,所以会经常用到定时任务。当然定时任务有很多种,本文我来介绍下我在项目中用到的quartz定时任务,项目架构采用的是微服务,主要写Spring Boot集成Quartz详解。

一、开发环境

   MySql、Mybatis、PageHelper、Spring Boot、Quartz

二、pom.xml依赖


            org.quartz-scheduler
            quartz
            2.2.1
        
        
            org.quartz-scheduler
            quartz-jobs
            2.2.1
        

三、application.properties配置

# 固定前缀org.quartz
# 定时任务开关,true-开  false-关
quartz.autoStartup=false
quartz.delaySeconds=10
org.quartz.scheduler.instanceName=DefaultQuartzScheduler
org.quartz.scheduler.instanceId=AUTO
org.quartz.scheduler.rmi.export=false
org.quartz.scheduler.rmi.proxy=false
org.quartz.scheduler.wrapJobExecutionInUserTransaction=false
org.quartz.threadPool.class=org.quartz.simpl.SimpleThreadPool
# 并发个数
org.quartz.threadPool.threadCount=10
# 优先级
org.quartz.threadPool.threadPriority=5
org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread=true
org.quartz.jobStore.misfireThreshold=5000
# 默认存储在内存中
#org.quartz.jobStore.class=org.quartz.simpl.RAMJobStore
#持久化
org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.StdJDBCDelegate
org.quartz.jobStore.class=org.quartz.impl.jdbcjobstore.JobStoreTX
org.quartz.jobStore.tablePrefix=QRTZ_
org.quartz.jobStore.dataSource=qzDS
org.quartz.dataSource.qzDS.maxConnections=10

四、quartzConfig配置

package com.fintech.modules.base.quartz;

import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.impl.StdScheduler;
import org.quartz.impl.StdSchedulerFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.beans.factory.config.PropertiesFactoryBean;
import org.springframework.context.ApplicationContext;
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 javax.sql.DataSource;
import java.io.IOException;
import java.util.Properties;

/**
 * @author lc
 * @date: 2017/12/4 15:03
 * @description: quartz配置加载类
 */
@Configuration
public class QuartzConfig {
    private Logger logger = LoggerFactory.getLogger(getClass());

    @Value("${quartz.autoStartup}")
    private Boolean autoStartup;

    @Value("${quartz.delaySeconds}")
    private Integer delaySeconds;

    @Value("${org.quartz.scheduler.instanceName}")
    private String schedulerInstanceName;

    @Value("${org.quartz.scheduler.rmi.export}")
    private String schedulerRmiExport;

    @Value("${org.quartz.scheduler.rmi.proxy}")
    private String schedulerRmiProxy;

    @Value("${org.quartz.scheduler.wrapJobExecutionInUserTransaction}")
    private String schedulerWrapJobExecutionInUserTransaction;

    @Value("${org.quartz.threadPool.class}")
    private String threadPoolClass;

    @Value("${org.quartz.threadPool.threadCount}")
    private String threadPoolThreadCount;

    @Value("${org.quartz.threadPool.threadPriority}")
    private String threadPoolThreadPriority;

    @Value("${org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread}")
    private String threadPoolThreadsInheritContextClassLoaderOfInitializingThread;

    @Value("${org.quartz.jobStore.misfireThreshold}")
    private String jobStoreMisfireThreshold;

    @Value("${org.quartz.jobStore.driverDelegateClass}")
    private String jobStoreDriverDelegateClass;

    @Value("${org.quartz.jobStore.class}")
    private String jobStoreClass;

    @Value("${org.quartz.jobStore.tablePrefix}")
    private String jobStoreTablePrefix;

    @Value("${org.quartz.jobStore.dataSource}")
    private String jobStoreDataSource;

    /*@Value("${org.quartz.dataSource.qzDS.maxConnections}")
    private String dataSourceMaxConnections;

    @Value("${spring.datasource.driver-class-name}")
    private String dataSourceDriver;

    @Value("${spring.datasource.url}")
    private String dataSourceURL;

    @Value("${spring.datasource.username}")
    private String dataSourceUser;

    @Value("${spring.datasource.password}")
    private String dataSourcePassword;*/

    @Bean
    public Properties quartzProperties() throws IOException {
        Properties quartzProperties = new Properties();
        quartzProperties.setProperty("org.quartz.scheduler.instanceName", schedulerInstanceName);
        quartzProperties.setProperty("org.quartz.scheduler.rmi.export", schedulerRmiExport);
        quartzProperties.setProperty("org.quartz.scheduler.rmi.proxy", schedulerRmiProxy);
        quartzProperties.setProperty("org.quartz.scheduler.wrapJobExecutionInUserTransaction", schedulerWrapJobExecutionInUserTransaction);
        quartzProperties.setProperty("org.quartz.threadPool.class", threadPoolClass);
        quartzProperties.setProperty("org.quartz.threadPool.threadCount", threadPoolThreadCount);
        quartzProperties.setProperty("org.quartz.threadPool.threadPriority", threadPoolThreadPriority);
        quartzProperties.setProperty("org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread", threadPoolThreadsInheritContextClassLoaderOfInitializingThread);
        quartzProperties.setProperty("org.quartz.jobStore.misfireThreshold", jobStoreMisfireThreshold);
        quartzProperties.setProperty("org.quartz.jobStore.class", jobStoreClass);
        quartzProperties.setProperty("org.quartz.jobStore.driverDelegateClass", jobStoreDriverDelegateClass);
        quartzProperties.setProperty("org.quartz.jobStore.tablePrefix", jobStoreTablePrefix);
        quartzProperties.setProperty("org.quartz.jobStore.dataSource", jobStoreDataSource);
        /*quartzProperties.setProperty("org.quartz.dataSource.qzDS.maxConnections", dataSourceMaxConnections);
        quartzProperties.setProperty("org.quartz.dataSource.qzDS.driver", dataSourceDriver);
        quartzProperties.setProperty("org.quartz.dataSource.qzDS.URL", dataSourceURL);
        quartzProperties.setProperty("org.quartz.dataSource.qzDS.user", dataSourceUser);
        quartzProperties.setProperty("org.quartz.dataSource.qzDS.password", dataSourcePassword);*/

        return quartzProperties;
    }

    @Bean
    public SchedulerFactoryBean schedulerFactoryBean(DataSource dataSource) throws IOException {
        logger.info("开始配置quartz定时任务");
        SchedulerFactoryBean factory = new SchedulerFactoryBean();
        // 加载quartz数据源配置
        factory.setQuartzProperties(quartzProperties());
        // 加载数据源
        factory.setDataSource(dataSource);
        // 将spring上下文放入quartz中, 用于在job执行时获取注入bean
        factory.setApplicationContextSchedulerContextKey("applicationContextKey");

        factory.setOverwriteExistingJobs(true);

        if(autoStartup) {
            // 延时启动
            if(delaySeconds > 0) {
                factory.setStartupDelay(delaySeconds);
            }
            logger.info("quartz开启自动启动定时任务, 延时{}s启动", delaySeconds);
        } else {
            factory.setAutoStartup(false);
            logger.warn("quartz未开启自动启动定时任务");
        }

        logger.info("quartz定时任务配置成功");
        return factory;
    }
}

五、实现

1、新建Java Bean
package com.fintech.modules.quartzjobmanage.dto;

/**
 * @Description: 定时任务bean
 * @author lc
 * @date 2018年5月29日
 */
public class JobAndTriggerDTO {
	/**
	 * 任务名称
	 */
	private String jobName;
	
	/**
	 * 任务所在组
	 */
	private String jobGroup;
	
	/**
	 * 任务类名
	 */
	private String jobClassName;
	
	/**
	 * 触发器名称
	 */
	private String triggerName;
	
	/**
	 * 触发器所在组
	 */
	private String triggerGroup;
	
	/**
	 * 表达式
	 */
	private String cronExpression;
	
	/**
	 * 时区
	 */
	private String timeZoneId;
	
	/**
	 * 状态
	 */
	private String triggerStart;
	
	/**
	 * 创建时间
	 */
	private String startTime;
	
	/**
	 * 上次执行时间
	 */
	private String prevFireTime;
	
	/**
	 * 下次执行时间
	 */
	private String nextFireTime;
	
	public String getTriggerStart() {
		return triggerStart;
	}
	public void setTriggerStart(String triggerStart) {
		this.triggerStart = triggerStart;
	}
	public String getStartTime() {
		return startTime;
	}
	public void setStartTime(String startTime) {
		this.startTime = startTime;
	}
	public String getPrevFireTime() {
		return prevFireTime;
	}
	public void setPrevFireTime(String prevFireTime) {
		this.prevFireTime = prevFireTime;
	}
	public String getNextFireTime() {
		return nextFireTime;
	}
	public void setNextFireTime(String nextFireTime) {
		this.nextFireTime = nextFireTime;
	}
	public String getJobName() {
		return jobName;
	}
	public void setJobName(String jobName) {
		this.jobName = jobName;
	}
	public String getJobGroup() {
		return jobGroup;
	}
	public void setJobGroup(String jobGroup) {
		this.jobGroup = jobGroup;
	}
	public String getJobClassName() {
		return jobClassName;
	}
	public void setJobClassName(String jobClassName) {
		this.jobClassName = jobClassName;
	}
	public String getTriggerName() {
		return triggerName;
	}
	public void setTriggerName(String triggerName) {
		this.triggerName = triggerName;
	}
	public String getTriggerGroup() {
		return triggerGroup;
	}
	public void setTriggerGroup(String triggerGroup) {
		this.triggerGroup = triggerGroup;
	}
	public String getCronExpression() {
		return cronExpression;
	}
	public void setCronExpression(String cronExpression) {
		this.cronExpression = cronExpression;
	}
	public String getTimeZoneId() {
		return timeZoneId;
	}
	public void setTimeZoneId(String timeZoneId) {
		this.timeZoneId = timeZoneId;
	}
}
2、xml

  
  
    

    
3、dao
package com.fintech.modules.quartzjobmanage.dao;

import java.util.List;
import org.apache.ibatis.annotations.Mapper;
import com.fintech.modules.quartzjobmanage.dto.JobAndTriggerDTO;

/**
 * @Description: 定时任务dao
 * @author lc
 * @date 2018年5月29日
 */
@Mapper
public interface JobAndTriggerMapper {
	
	/**
	 * @Description: 查询定时任务信息
	 * @author lc
	 */
	public List getJobAndTriggerDetails();
}
4、service
package com.fintech.modules.quartzjobmanage.service;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.fintech.modules.quartzjobmanage.dao.JobAndTriggerMapper;
import com.fintech.modules.quartzjobmanage.dto.JobAndTriggerDTO;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;

/**
 * @Description: 定时任务service
 * @author lc
 * @date 2018年5月29日
 */
@Service
public class JobAndTriggerService{

	@Autowired
	private JobAndTriggerMapper jobAndTriggerMapper;
	
	/**
	 * @Description: 查询定时任务信息
	 * @author lc
	 */
	public PageInfo getJobAndTriggerDetails(int pageNum, int pageSize) {
		PageHelper.startPage(pageNum, pageSize);
		List list = jobAndTriggerMapper.getJobAndTriggerDetails();
		PageInfo page = new PageInfo(list);
		return page;
	}

}
5、controller
package com.fintech.modules.quartzjobmanage.controller;

import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;

import java.util.HashMap;
import java.util.Map;

import org.apache.commons.lang3.StringUtils;
import org.quartz.CronScheduleBuilder;
import org.quartz.CronTrigger;
import org.quartz.JobBuilder;
import org.quartz.JobDetail;
import org.quartz.JobKey;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.TriggerBuilder;
import org.quartz.TriggerKey;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.quartz.QuartzJobBean;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;

import com.fintech.modules.base.util.SmsException;
import com.fintech.modules.quartzjobmanage.dto.JobAndTriggerDTO;
import com.fintech.modules.quartzjobmanage.service.JobAndTriggerService;
import com.fintech.modules.sms.common.dto.LayuiResult;
import com.github.pagehelper.PageInfo;

/**
 * @author xujunqi
 * @date: 2017/12/9 15:24
 * @description: 定时任务配置控制类
 */
@RestController
@RequestMapping(value = "/quartzjob")
@Api(tags="定时任务配置控制类")
public class QuartzJobController {
    private static Logger logger = LoggerFactory.getLogger(QuartzJobController.class);

    @Autowired
    private Scheduler scheduler;
    @Autowired 
    private JobAndTriggerService jobAndTriggerService;
    
    @ApiOperation(value= "添加定时任务", notes= "添加定时任务")
    @PostMapping(value = "/addjob")
    public String addjobController(@RequestParam(value = "jobClassName") String jobClassName,
                                 @RequestParam(value = "jobGroupName") String jobGroupName,
                                 @RequestParam(value = "cronExpression") String cronExpression) throws Exception {
        addJob(jobClassName, jobGroupName, cronExpression);

        return "定时任务添加成功";
    }

    public void addJob(String jobClassName, String jobGroupName, String cronExpression) throws Exception {
        if(StringUtils.isBlank(jobGroupName)) {
            jobGroupName = Scheduler.DEFAULT_GROUP;
        }
        // 启动调度器
        scheduler.start();
        //构建job信息
        JobDetail jobDetail = JobBuilder.newJob(getClass(jobClassName).getClass()).withIdentity(jobClassName, jobGroupName).build();
        //表达式调度构建器(即任务执行的时间)
        CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(cronExpression);
        //按新的cronExpression表达式构建一个新的trigger
        CronTrigger trigger = TriggerBuilder.newTrigger().withIdentity(jobClassName, jobGroupName)
                .withSchedule(scheduleBuilder).build();
        try {
            scheduler.scheduleJob(jobDetail, trigger);
        } catch (SchedulerException e) {
            logger.error("创建定时任务失败", e);
            throw new SmsException("创建定时任务失败");
        }
    }
    
/*    @ApiOperation(value= "根据条件查询定时任务", notes= "根据条件查询定时任务")
    @PostMapping(value = "/queryjob")
    public String queryjob(@RequestParam(value = "jobClassName") String jobClassName, @RequestParam(value = "jobGroupName") String jobGroupName) throws Exception {
        jobPause(jobClassName, jobGroupName);

        return "定时任务暂停成功";
    }*/

    @ApiOperation(value= "根据条件暂停定时任务", notes= "根据条件暂停定时任务")
    @PostMapping(value = "/pausejob")
    public String pausejob(@RequestParam(value = "jobClassName") String jobClassName, @RequestParam(value = "jobGroupName") String jobGroupName) throws Exception {
        jobPause(jobClassName, jobGroupName);

        return "定时任务暂停成功";
    }

    public void jobPause(String jobClassName, String jobGroupName) throws Exception {
        if(StringUtils.isBlank(jobGroupName)) {
            jobGroupName = Scheduler.DEFAULT_GROUP;
        }
        // 通过SchedulerFactory获取一个调度器实例
        scheduler.pauseJob(JobKey.jobKey(jobClassName, jobGroupName));
    }

    @ApiOperation(value= "根据条件恢复定时任务", notes= "根据条件恢复定时任务")
    @PostMapping(value = "/resumejob")
    public String resumejob(@RequestParam(value = "jobClassName") String jobClassName, @RequestParam(value = "jobGroupName") String jobGroupName) throws Exception {
        jobresume(jobClassName, jobGroupName);

        return "定时任务恢复成功";
    }

    public void jobresume(String jobClassName, String jobGroupName) throws Exception {
        if(StringUtils.isBlank(jobGroupName)) {
            jobGroupName = Scheduler.DEFAULT_GROUP;
        }
        // 通过SchedulerFactory获取一个调度器实例
        scheduler.resumeJob(JobKey.jobKey(jobClassName, jobGroupName));
    }

    @ApiOperation(value= "根据条件定时任务", notes= "根据条件定时任务")
    @PostMapping(value = "/reschedulejob")
    public String rescheduleJob(@RequestParam(value = "jobClassName") String jobClassName,
                              @RequestParam(value = "jobGroupName") String jobGroupName,
                              @RequestParam(value = "cronExpression") String cronExpression) throws Exception {
        jobreschedule(jobClassName, jobGroupName, cronExpression);

        return "定时任务重新调度成功";
    }

    public void jobreschedule(String jobClassName, String jobGroupName, String cronExpression) throws Exception {
        if(StringUtils.isBlank(jobGroupName)) {
            jobGroupName = Scheduler.DEFAULT_GROUP;
        }

        try {
            TriggerKey triggerKey = TriggerKey.triggerKey(jobClassName, jobGroupName);
            // 表达式调度构建器
            CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(cronExpression);
            CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);
            // 按新的cronExpression表达式重新构建trigger
            trigger = trigger.getTriggerBuilder().withIdentity(triggerKey).withSchedule(scheduleBuilder).build();
            // 按新的trigger重新设置job执行
            scheduler.rescheduleJob(triggerKey, trigger);
        } catch (SchedulerException e) {
            logger.error("更新定时任务失败", e);
            throw new SmsException("更新定时任务失败");
        }
    }

    @ApiOperation(value= "根据条件删除定时任务", notes= "根据条件删除定时任务")
    @PostMapping(value = "/deletejob")
    public String deletejob(@RequestParam(value = "jobClassName") String jobClassName, @RequestParam(value = "jobGroupName") String jobGroupName) throws Exception {
        jobdelete(jobClassName, jobGroupName);

        return "定时任务删除成功";
    }

    public void jobdelete(String jobClassName, String jobGroupName) throws Exception {
        if(StringUtils.isBlank(jobGroupName)) {
            jobGroupName = Scheduler.DEFAULT_GROUP;
        }

        // 通过SchedulerFactory获取一个调度器实例
        scheduler.pauseTrigger(TriggerKey.triggerKey(jobClassName, jobGroupName));//停止触发器  
        scheduler.unscheduleJob(TriggerKey.triggerKey(jobClassName, jobGroupName));//移除触发器 
        scheduler.deleteJob(JobKey.jobKey(jobClassName, jobGroupName));//删除任务  
    }

    /**
     * @Description: 定时任务管理
     * @author lc
     */
    @ApiOperation(value= "定时任务管理", notes= "根据条件管理定时任务")
    @GetMapping(value = "/queryjob")
    public Map queryjob(@RequestParam(value = "pageNum") Integer pageNum, @RequestParam(value = "pageSize") Integer pageSize) {
        PageInfo jobAndTrigger = jobAndTriggerService.getJobAndTriggerDetails(pageNum, pageSize);
        Map map = new HashMap();
        map.put("JobAndTrigger", jobAndTrigger);
        map.put("number", jobAndTrigger.getTotal());
        return map;
    }
    
    /**
     * @Description: 查询定时任务
     * @author lc
     */
    @ApiOperation(value= "查询定时任务", notes= "根据条件查询定时任务")
    @GetMapping(value = "/queryJobList")
    public LayuiResult queryJobList(@RequestParam Map paramMap) {
        PageInfo list = jobAndTriggerService.getJobAndTriggerDetails(Integer.parseInt(paramMap.get("page").toString()), Integer.parseInt(paramMap.get("limit").toString()));
        return LayuiResult.data(list.getTotal(), list.getList());
    }

    public static QuartzJobBean getClass(String classname) throws Exception {
        Class class1 = Class.forName(classname);
        return (QuartzJobBean) class1.newInstance();
    }

}
6、设置定时任务例子
package com.fintech.modules.base.quartzjobs;

import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.quartz.SchedulerContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.scheduling.quartz.QuartzJobBean;
import org.springframework.stereotype.Component;

import com.fintech.modules.sms.smsreport.service.SmsLogStatusReportService;

/**
 * @Description: 每分钟/短信报文统计发送状态
 * @author lc
 * @date 2018年4月10日
 * 每2分钟统计一次
 */
@Component
public class SmsReportStatisJob extends QuartzJobBean {
    private static final long serialVersionUID = 1L;
    private Logger logger = LoggerFactory.getLogger(this.getClass());
    
    @Override
    protected void executeInternal(JobExecutionContext context) throws JobExecutionException {
    	logger.info("开始执行-定时短信发送报文统计:{}");
        try {
            SchedulerContext cont = context.getScheduler().getContext();
            ApplicationContext appCtx = (ApplicationContext) cont.get("applicationContextKey");
            // 调用具体sercive业务代码
            SmsLogStatusReportService service = appCtx.getBean(SmsLogStatusReportService.class);
            service.smsReportStatis();
        } catch (Exception e) {
            logger.error("每分钟/短信报文跑批统计发送状态异常!{}", e);
        } 
        logger.info("执行结束-定时短信发送报文统计:{}");
    }
}

六、页面管理

在Spring Boot的工程中,静态页面可以放在资源文件static目录下,controller已经写好了,页面完全按照自己的需求去实现即可,下面是我拷贝别人的管理页面,这里贴一下代码





定时任务








	
查询 添加

© Quartz 任务管理


你可能感兴趣的:(Spring,Cloud,Spring,Boot,Quartz,定时任务)