赞
踩
<!-- quartz定时任务 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-quartz</artifactId>
</dependency>
spring:
datasource:
url: jdbc:mysql://127.0.0.1:3306/quartzJob?allowMultiQueries=true&useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=Asia/Shanghai
password: root
username: root
driver-class-name: com.mysql.cj.jdbc.Driver
quartz:
job-store-type: jdbc
jdbc:
initialize-schema: always
spring: ## quartz定时任务,采用数据库方式 quartz: job-store-type: jdbc initialize-schema: embedded #定时任务启动开关,true-开 false-关 auto-startup: true #延迟1秒启动定时任务 startup-delay: 1s #启动时更新己存在的Job overwrite-existing-jobs: true properties: org: quartz: scheduler: instanceName: MyScheduler instanceId: AUTO jobStore: class: org.springframework.scheduling.quartz.LocalDataSourceJobStore driverDelegateClass: org.quartz.impl.jdbcjobstore.StdJDBCDelegate tablePrefix: QRTZ_ isClustered: false misfireThreshold: 12000 clusterCheckinInterval: 15000 threadPool: class: org.quartz.simpl.SimpleThreadPool threadCount: 1 threadPriority: 5 threadsInheritContextClassLoaderOfInitializingThread: true
注意:
1、如果需要quartz 第一次运行时自动生成 quartz 所需的表那么 quartzJob? 后面的配置为 :allowMultiQueries=true&useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=Asia/Shanghai
待第一次运行后可以再根据自己的需要修改
2、配置文件中的 initialize-schema: always 配置的 always 属性意思是,每次初始化都会重新生成表(执行一次删除,执行一次创建),生成后,可以修改为 never
只有以上两个条件同时配置满足,才能使quartz 在第一次运行时,自动生成所需的表
在quartz的ja包org.quartz.impl.jdbcjobstore路径下,如下图
CREATE TABLE `sys_quartz_job` (
`id` varchar(32) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL,
`create_by` varchar(32) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT NULL COMMENT '创建人',
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
`del_flag` int DEFAULT NULL COMMENT '删除状态',
`update_by` varchar(32) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT NULL COMMENT '修改人',
`update_time` datetime DEFAULT NULL COMMENT '修改时间',
`job_class_name` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT NULL COMMENT '任务类名',
`cron_expression` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT NULL COMMENT 'cron表达式',
`parameter` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT NULL COMMENT '参数',
`meeting_record_id` int DEFAULT NULL COMMENT '会议室记录id',
`description` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT NULL COMMENT '描述',
`status` int DEFAULT NULL COMMENT '状态 0正常 -1停止',
PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 ROW_FORMAT=DYNAMIC;
package org.jeecg.modules.quartz.controller; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import lombok.extern.slf4j.Slf4j; import org.apache.shiro.SecurityUtils; import org.jeecg.common.api.vo.Result; import org.jeecg.common.constant.CommonConstant; import org.jeecg.common.constant.SymbolConstant; import org.jeecg.common.system.query.QueryGenerator; import org.jeecg.common.system.vo.LoginUser; import org.jeecg.common.util.ImportExcelUtil; import org.jeecg.modules.quartz.entity.QuartzJob; import org.jeecg.modules.quartz.service.IQuartzJobService; import org.jeecgframework.poi.excel.ExcelImportUtil; import org.jeecgframework.poi.excel.def.NormalExcelConstants; import org.jeecgframework.poi.excel.entity.ExportParams; import org.jeecgframework.poi.excel.entity.ImportParams; import org.jeecgframework.poi.excel.view.JeecgEntityExcelView; import org.quartz.Scheduler; import org.quartz.SchedulerException; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.*; import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartHttpServletRequest; import org.springframework.web.servlet.ModelAndView; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Map; /** * @Description: 定时任务 */ @RestController @RequestMapping("/sys/quartzJob") @Slf4j @Api(tags = "定时任务接口") public class QuartzJobController { @Autowired private IQuartzJobService quartzJobService; @Autowired private Scheduler scheduler; /** * 分页列表查询 * * @param quartzJob * @param pageNo * @param pageSize * @param req * @return */ @RequestMapping(value = "/list", method = RequestMethod.GET) public Result<?> queryPageList(QuartzJob quartzJob, @RequestParam(name = "pageNo", defaultValue = "1") Integer pageNo, @RequestParam(name = "pageSize", defaultValue = "10") Integer pageSize, HttpServletRequest req) { QueryWrapper<QuartzJob> queryWrapper = QueryGenerator.initQueryWrapper(quartzJob, req.getParameterMap()); Page<QuartzJob> page = new Page<QuartzJob>(pageNo, pageSize); IPage<QuartzJob> pageList = quartzJobService.page(page, queryWrapper); return Result.ok(pageList); } /** * 添加定时任务 * * @param quartzJob * @return */ //@RequiresRoles("admin") @RequestMapping(value = "/add", method = RequestMethod.POST) public Result<?> add(@RequestBody QuartzJob quartzJob) { quartzJobService.saveAndScheduleJob(quartzJob); return Result.ok("创建定时任务成功"); } /** * 更新定时任务 * * @param quartzJob * @return */ //@RequiresRoles("admin") @RequestMapping(value = "/edit", method ={RequestMethod.PUT, RequestMethod.POST}) public Result<?> eidt(@RequestBody QuartzJob quartzJob) { try { quartzJobService.editAndScheduleJob(quartzJob); } catch (SchedulerException e) { log.error(e.getMessage(),e); return Result.error("更新定时任务失败!"); } return Result.ok("更新定时任务成功!"); } /** * 通过id删除 * * @param id * @return */ //@RequiresRoles("admin") @RequestMapping(value = "/delete", method = RequestMethod.DELETE) public Result<?> delete(@RequestParam(name = "id", required = true) String id) { QuartzJob quartzJob = quartzJobService.getById(id); if (quartzJob == null) { return Result.error("未找到对应实体"); } quartzJobService.deleteAndStopJob(id); return Result.ok("删除成功!"); } /** * 批量删除 * * @param ids * @return */ //@RequiresRoles("admin") @RequestMapping(value = "/deleteBatch", method = RequestMethod.DELETE) public Result<?> deleteBatch(@RequestParam(name = "ids", required = true) String ids) { if (ids == null || "".equals(ids.trim())) { return Result.error("参数不识别!"); } for (String id : Arrays.asList(ids.split(SymbolConstant.COMMA))) { QuartzJob job = quartzJobService.getById(id); quartzJobService.deleteAndStopJob(id); } return Result.ok("删除定时任务成功!"); } /** * 暂停定时任务 * * @param id * @return */ //@RequiresRoles("admin") @GetMapping(value = "/pause") @ApiOperation(value = "停止定时任务") public Result<Object> pauseJob(@RequestParam(name = "id") String id) { QuartzJob job = quartzJobService.getById(id); if (job == null) { return Result.error("定时任务不存在!"); } quartzJobService.pause(job); return Result.ok("停止定时任务成功"); } /** * 启动定时任务 * * @param id * @return */ //@RequiresRoles("admin") @GetMapping(value = "/resume") @ApiOperation(value = "启动定时任务") public Result<Object> resumeJob(@RequestParam(name = "id") String id) { QuartzJob job = quartzJobService.getById(id); if (job == null) { return Result.error("定时任务不存在!"); } quartzJobService.resumeJob(job); //scheduler.resumeJob(JobKey.jobKey(job.getJobClassName().trim())); return Result.ok("启动定时任务成功"); } /** * 通过id查询 * * @param id * @return */ @RequestMapping(value = "/queryById", method = RequestMethod.GET) public Result<?> queryById(@RequestParam(name = "id", required = true) String id) { QuartzJob quartzJob = quartzJobService.getById(id); return Result.ok(quartzJob); } /** * 导出excel * * @param request * @param quartzJob */ @RequestMapping(value = "/exportXls") public ModelAndView exportXls(HttpServletRequest request, QuartzJob quartzJob) { // Step.1 组装查询条件 QueryWrapper<QuartzJob> queryWrapper = QueryGenerator.initQueryWrapper(quartzJob, request.getParameterMap()); // Step.2 AutoPoi 导出Excel ModelAndView mv = new ModelAndView(new JeecgEntityExcelView()); List<QuartzJob> pageList = quartzJobService.list(queryWrapper); // 导出文件名称 mv.addObject(NormalExcelConstants.FILE_NAME, "定时任务列表"); mv.addObject(NormalExcelConstants.CLASS, QuartzJob.class); //获取当前登录用户 //update-begin---author:wangshuai ---date:20211227 for:[JTC-116]导出人写死了------------ LoginUser user = (LoginUser) SecurityUtils.getSubject().getPrincipal(); mv.addObject(NormalExcelConstants.PARAMS, new ExportParams("定时任务列表数据", "导出人:"+user.getRealname(), "导出信息")); //update-end---author:wangshuai ---date:20211227 for:[JTC-116]导出人写死了------------ mv.addObject(NormalExcelConstants.DATA_LIST, pageList); return mv; } /** * 通过excel导入数据 * * @param request * @param response * @return */ @RequestMapping(value = "/importExcel", method = RequestMethod.POST) public Result<?> importExcel(HttpServletRequest request, HttpServletResponse response) throws IOException { MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request; Map<String, MultipartFile> fileMap = multipartRequest.getFileMap(); // 错误信息 List<String> errorMessage = new ArrayList<>(); int successLines = 0, errorLines = 0; for (Map.Entry<String, MultipartFile> entity : fileMap.entrySet()) { // 获取上传文件对象 MultipartFile file = entity.getValue(); ImportParams params = new ImportParams(); params.setTitleRows(2); params.setHeadRows(1); params.setNeedSave(true); try { List<QuartzJob> listQuartzJobs = ExcelImportUtil.importExcel(file.getInputStream(), QuartzJob.class, params); //add-begin-author:taoyan date:20210909 for:导入定时任务,并不会被启动和调度,需要手动点击启动,才会加入调度任务中 #2986 for(QuartzJob job: listQuartzJobs){ job.setStatus(CommonConstant.STATUS_DISABLE); } List<String> list = ImportExcelUtil.importDateSave(listQuartzJobs, IQuartzJobService.class, errorMessage,CommonConstant.SQL_INDEX_UNIQ_JOB_CLASS_NAME); //add-end-author:taoyan date:20210909 for:导入定时任务,并不会被启动和调度,需要手动点击启动,才会加入调度任务中 #2986 errorLines+=list.size(); successLines+=(listQuartzJobs.size()-errorLines); } catch (Exception e) { log.error(e.getMessage(), e); return Result.error("文件导入失败!"); } finally { try { file.getInputStream().close(); } catch (IOException e) { e.printStackTrace(); } } } return ImportExcelUtil.imporReturnRes(errorLines,successLines,errorMessage); } /** * 立即执行 * @param id * @return */ //@RequiresRoles("admin") @GetMapping("/execute") public Result<?> execute(@RequestParam(name = "id", required = true) String id) { QuartzJob quartzJob = quartzJobService.getById(id); if (quartzJob == null) { return Result.error("未找到对应实体"); } try { quartzJobService.execute(quartzJob); } catch (Exception e) { //e.printStackTrace(); log.info("定时任务 立即执行失败>>"+e.getMessage()); return Result.error("执行失败!"); } return Result.ok("执行成功!"); } }
package org.jeecg.modules.quartz.service; import java.util.List; import org.jeecg.modules.quartz.entity.QuartzJob; import org.quartz.SchedulerException; import com.baomidou.mybatisplus.extension.service.IService; /** * @Description: 定时任务 */ public interface IQuartzJobService extends IService<QuartzJob> { /** * 通过类名寻找定时任务 * @param jobClassName 类名 * @return List<QuartzJob> */ List<QuartzJob> findByJobClassName(String jobClassName); /** * 保存定时任务 * @param quartzJob * @return boolean */ boolean saveAndScheduleJob(QuartzJob quartzJob); /** * 编辑定时任务 * @param quartzJob * @return boolean * @throws SchedulerException */ boolean editAndScheduleJob(QuartzJob quartzJob) throws SchedulerException; /** * 删除定时任务 * @param id * @return boolean */ boolean deleteAndStopJob(String id); /** * 恢复定时任务 * @param quartzJob * @return */ boolean resumeJob(QuartzJob quartzJob); /** * 执行定时任务 * @param quartzJob * @throws Exception */ void execute(QuartzJob quartzJob) throws Exception; /** * 暂停任务 * @param quartzJob * @throws SchedulerException */ void pause(QuartzJob quartzJob); }
package org.jeecg.modules.quartz.service.impl; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import lombok.extern.slf4j.Slf4j; import org.jeecg.common.constant.CommonConstant; import org.jeecg.common.exception.JeecgBootException; import org.jeecg.common.util.DateUtils; import org.jeecg.modules.quartz.entity.QuartzJob; import org.jeecg.modules.quartz.mapper.QuartzJobMapper; import org.jeecg.modules.quartz.service.IQuartzJobService; import org.quartz.*; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.util.Date; import java.util.List; /** * @Description: 定时任务 */ @Slf4j @Service public class QuartzJobServiceImpl extends ServiceImpl<QuartzJobMapper, QuartzJob> implements IQuartzJobService { @Autowired private QuartzJobMapper quartzJobMapper; @Autowired private Scheduler scheduler; /** * 立即执行的任务分组 */ private static final String JOB_TEST_GROUP = "test_group"; @Override public List<QuartzJob> findByJobClassName(String jobClassName) { return quartzJobMapper.findByJobClassName(jobClassName); } /** * 保存&启动定时任务 */ @Override @Transactional(rollbackFor = JeecgBootException.class) public boolean saveAndScheduleJob(QuartzJob quartzJob) { // DB设置修改 quartzJob.setDelFlag(CommonConstant.DEL_FLAG_0); boolean success = this.save(quartzJob); if (success) { if (CommonConstant.STATUS_NORMAL.equals(quartzJob.getStatus())) { // 定时器添加 this.schedulerAdd(quartzJob.getId(), quartzJob.getJobClassName().trim(), quartzJob.getCronExpression().trim(), quartzJob.getParameter()); } } return success; } /** * 恢复定时任务 */ @Override @Transactional(rollbackFor = JeecgBootException.class) public boolean resumeJob(QuartzJob quartzJob) { schedulerDelete(quartzJob.getId()); schedulerAdd(quartzJob.getId(), quartzJob.getJobClassName().trim(), quartzJob.getCronExpression().trim(), quartzJob.getParameter()); quartzJob.setStatus(CommonConstant.STATUS_NORMAL); return this.updateById(quartzJob); } /** * 编辑&启停定时任务 * @throws SchedulerException */ @Override @Transactional(rollbackFor = JeecgBootException.class) public boolean editAndScheduleJob(QuartzJob quartzJob) throws SchedulerException { if (CommonConstant.STATUS_NORMAL.equals(quartzJob.getStatus())) { schedulerDelete(quartzJob.getId()); schedulerAdd(quartzJob.getId(), quartzJob.getJobClassName().trim(), quartzJob.getCronExpression().trim(), quartzJob.getParameter()); }else{ scheduler.pauseJob(JobKey.jobKey(quartzJob.getId())); } return this.updateById(quartzJob); } /** * 删除&停止删除定时任务 */ @Override @Transactional(rollbackFor = JeecgBootException.class) public boolean deleteAndStopJob(String id) { schedulerDelete(id); boolean ok = this.removeById(id); return ok; } @Override public void execute(QuartzJob quartzJob) throws Exception { String jobName = quartzJob.getJobClassName().trim(); Date startDate = new Date(); String ymd = DateUtils.date2Str(startDate,DateUtils.yyyymmddhhmmss.get()); String identity = jobName + ymd; //3秒后执行 只执行一次 // update-begin--author:sunjianlei ---- date:20210511--- for:定时任务立即执行,延迟3秒改成0.1秒------- startDate.setTime(startDate.getTime() + 100L); // update-end--author:sunjianlei ---- date:20210511--- for:定时任务立即执行,延迟3秒改成0.1秒------- // 定义一个Trigger SimpleTrigger trigger = (SimpleTrigger)TriggerBuilder.newTrigger() .withIdentity(identity, JOB_TEST_GROUP) .startAt(startDate) .build(); // 构建job信息 JobDetail jobDetail = JobBuilder.newJob(getClass(jobName).getClass()).withIdentity(identity).usingJobData("parameter", quartzJob.getParameter()).build(); // 将trigger和 jobDetail 加入这个调度 scheduler.scheduleJob(jobDetail, trigger); // 启动scheduler scheduler.start(); } @Override @Transactional(rollbackFor = JeecgBootException.class) public void pause(QuartzJob quartzJob){ schedulerDelete(quartzJob.getId()); quartzJob.setStatus(CommonConstant.STATUS_DISABLE); this.updateById(quartzJob); } /** * 添加定时任务 * * @param jobClassName * @param cronExpression * @param parameter */ private void schedulerAdd(String id, String jobClassName, String cronExpression, String parameter) { try { // 启动调度器 scheduler.start(); // 构建job信息 JobDetail jobDetail = JobBuilder.newJob(getClass(jobClassName).getClass()).withIdentity(id).usingJobData("parameter", parameter).build(); // 表达式调度构建器(即任务执行的时间) CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(cronExpression); // 按新的cronExpression表达式构建一个新的trigger CronTrigger trigger = TriggerBuilder.newTrigger().withIdentity(id).withSchedule(scheduleBuilder).build(); scheduler.scheduleJob(jobDetail, trigger); } catch (SchedulerException e) { throw new JeecgBootException("创建定时任务失败", e); } catch (RuntimeException e) { throw new JeecgBootException(e.getMessage(), e); }catch (Exception e) { throw new JeecgBootException("后台找不到该类名:" + jobClassName, e); } } /** * 删除定时任务 * * @param id */ private void schedulerDelete(String id) { try { scheduler.pauseTrigger(TriggerKey.triggerKey(id)); scheduler.unscheduleJob(TriggerKey.triggerKey(id)); scheduler.deleteJob(JobKey.jobKey(id)); } catch (Exception e) { log.error(e.getMessage(), e); throw new JeecgBootException("删除定时任务失败"); } } private static Job getClass(String classname) throws Exception { Class<?> class1 = Class.forName(classname); return (Job) class1.newInstance(); } }
package org.jeecg.modules.quartz.mapper; import java.util.List; import org.apache.ibatis.annotations.Param; import org.jeecg.modules.quartz.entity.QuartzJob; import com.baomidou.mybatisplus.core.mapper.BaseMapper; /** * @Description: 定时任务 */ public interface QuartzJobMapper extends BaseMapper<QuartzJob> { /** * 根据jobClassName查询 * @param jobClassName 任务类名 * @return */ public List<QuartzJob> findByJobClassName(@Param("jobClassName") String jobClassName); }
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="org.jeecg.modules.quartz.mapper.QuartzJobMapper">
<!-- 根据jobClassName查询 -->
<select id="findByJobClassName" resultType="org.jeecg.modules.quartz.entity.QuartzJob">
select * from sys_quartz_job where job_class_name = #{jobClassName}
</select>
</mapper>
package org.jeecg.modules.quartz.entity; import java.io.Serializable; import org.jeecg.common.aspect.annotation.Dict; import org.jeecgframework.poi.excel.annotation.Excel; import org.springframework.format.annotation.DateTimeFormat; import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; import com.fasterxml.jackson.annotation.JsonFormat; import lombok.Data; /** * @Description: 定时任务 */ @Data @TableName("sys_quartz_job") public class QuartzJob implements Serializable { private static final long serialVersionUID = 1L; /** * id */ @TableId(type = IdType.ASSIGN_ID) private java.lang.String id; /** * 创建人 */ private java.lang.String createBy; /** * 创建时间 */ @JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss") @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") private java.util.Date createTime; /** * 删除状态 */ private java.lang.Integer delFlag; /** * 修改人 */ private java.lang.String updateBy; /** * 修改时间 */ @JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss") @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") private java.util.Date updateTime; /** * 任务类名 */ @Excel(name = "任务类名", width = 40) private java.lang.String jobClassName; /** * cron表达式 */ @Excel(name = "cron表达式", width = 30) private java.lang.String cronExpression; /** * 参数 */ @Excel(name = "参数", width = 15) private java.lang.String parameter; /** * 描述 */ @Excel(name = "描述", width = 40) private java.lang.String description; /** * 状态 0正常 -1停止 */ @Excel(name = "状态", width = 15, dicCode = "quartz_status") @Dict(dicCode = "quartz_status") private java.lang.Integer status; }
如果调度器要执行任务,首先得要有一个任务相关的类
写了3个平常的案例,一个是不带参数同步的,一个是不带参数的,一个是带参数的
package org.jeecg.modules.quartz.job; import lombok.extern.slf4j.Slf4j; import org.jeecg.common.util.DateUtils; import org.quartz.*; /** * @Description: 同步定时任务测试 * * 此处的同步是指 当定时任务的执行时间大于任务的时间间隔时 * 会等待第一个任务执行完成才会走第二个任务 */ @PersistJobDataAfterExecution // 持久化JobDataMap里的数据,使下一个定时任务还能获取到这些值 @DisallowConcurrentExecution // 禁止并发多任务执行,所以永远只有一个任务在执行中 @Slf4j public class AsyncJob implements Job { @Override public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException { log.info(" --- 同步任务调度开始 --- " + " Job Execution key:"+jobExecutionContext.getJobDetail().getKey()); try { //此处模拟任务执行时间 5秒 任务表达式配置为每秒执行一次:0/1 * * * * ? * Thread.sleep(20000); } catch (InterruptedException e) { e.printStackTrace(); } //测试发现 每5秒执行一次 log.info(" --- 执行完毕,时间:"+DateUtils.now()+"---" + " 线程名"+ Thread.currentThread().getName() ); } }
package org.jeecg.modules.quartz.job; import org.jeecg.common.util.DateUtils; import org.quartz.Job; import org.quartz.JobExecutionContext; import org.quartz.JobExecutionException; import lombok.extern.slf4j.Slf4j; /** * 示例不带参定时任务 */ @Slf4j public class SampleJob implements Job { @Override public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException { log.info(" Job Execution key:"+jobExecutionContext.getJobDetail().getKey()); log.info(String.format(" Jeecg-Boot 普通定时任务 SampleJob ! 时间:" + DateUtils.getTimestamp())); } }
package org.jeecg.modules.quartz.job; import org.jeecg.common.util.DateUtils; import org.quartz.Job; import org.quartz.JobExecutionContext; import org.quartz.JobExecutionException; import lombok.extern.slf4j.Slf4j; /** * 示例带参定时任务 */ @Slf4j public class SampleParamJob implements Job { /** * 若参数变量名修改 QuartzJobController中也需对应修改 */ private String parameter; public void setParameter(String parameter) { this.parameter = parameter; } @Override public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException { log.info(" Job Execution key:"+jobExecutionContext.getJobDetail().getKey()); log.info( String.format("welcome %s! Jeecg-Boot 带参数定时任务 SampleParamJob ! 时间:" + DateUtils.now(), this.parameter)); } }
这是带参一次性任务,添加任务成功后,会在表qrtz_job_details生成一条待处理任务,处理完成后,会删除此记录,如果是循环任务会一直存在
MisFire策略常量的定义在类CronTrigger中,列举如下:
MISFIRE_INSTRUCTION_FIRE_ONCE_NOW = 1
MISFIRE_INSTRUCTION_DO_NOTHING = 2
MISFIRE_INSTRUCTION_SMART_POLICY = 0
MISFIRE_INSTRUCTION_IGNORE_MISFIRE_POLICY = -1
根据JavaDoc介绍和官网文档分析,其对应执行策略如下:
MISFIRE_INSTRUCTION_FIRE_ONCE_NOW:立即执行一次,然后按照Cron定义时间点执行
MISFIRE_INSTRUCTION_DO_NOTHING:什么都不做,等待Cron定义下次任务执行的时间点
MISFIRE_INSTRUCTION_SMART_POLICY:智能的策略,针对不同的Trigger执行不同,CronTrigger时为MISFIRE_INSTRUCTION_FIRE_ONCE_NOW
MISFIRE_INSTRUCTION_IGNORE_MISFIRE_POLICY:将所有错过的执行时间点全都补上,例如,任务15s执行一次,执行的任务错过了4分钟,则执行MisFire时,一次性执行4*(60/15)= 16次任务
影响misFire执行策略的另一个参数就是misfireThreshold
package org.jeecg.modules.quartz.job; import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; import org.jeecg.common.util.DateUtils; import org.quartz.Job; import org.quartz.JobExecutionContext; import org.quartz.JobExecutionException; /** * 示例不带参定时任务 */ @Slf4j public class SampleJob implements Job { @Override public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException { log.info(" Job Execution key:"+jobExecutionContext.getJobDetail().getKey()); int a=0; try { a=a/a; } catch (Exception e) { log.error("执行任务出错了..."); try { Thread.sleep(2000); } catch (InterruptedException e1) { e1.printStackTrace(); } JobExecutionException e2 = new JobExecutionException(e); // this job will refire immediately e2.setRefireImmediately(true); throw e2; } log.info(String.format(" Jeecg-Boot 普通定时任务 SampleJob ! 时间:" + DateUtils.getTimestamp())); } }
定时任务会根据任务执行线程池来执行,Spring中默认配置的任务执行线程池数量是1
通过在项目中增加以下配置,增加任务执行线程池数量来提升并发执行能力:
@Configuration
public class ScheduledConfig {
@Bean
public TaskScheduler taskScheduler() {
ThreadPoolTaskScheduler taskScheduler = new ThreadPoolTaskScheduler();
taskScheduler.setPoolSize(10);
return taskScheduler;
}
}
@Configuration @EnableScheduling @Slf4j public class ScheduledConfig implements SchedulingConfigurer { @Override public void configureTasks(ScheduledTaskRegistrar scheduledTaskRegistrar) { TaskScheduler scheduler = this.taskScheduler(); scheduledTaskRegistrar.setTaskScheduler(scheduler); } @Bean(destroyMethod = "shutdown") public ThreadPoolTaskScheduler taskScheduler() { ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler(); scheduler.setPoolSize(10); scheduler.setThreadNamePrefix("task-"); scheduler.setAwaitTerminationSeconds(60); scheduler.setWaitForTasksToCompleteOnShutdown(true); return scheduler; }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。