前几天公司里涉及到了一个定时任务的模块,不是很理解其原理,完全照着前人的路线重新敲了一遍,这两天空下来自己找了点资料来学习来,在自己的框架里搭建了quartz。
先建立一个实体类通过查询数据库里的数据来定下要执行的task
@Data
@Entity
@Table(name = "quartz_job")
public class QuartzJob implements Serializable {
public static final String JOB_KEY = "JOB_KEY";
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@NotNull(groups = {Update.class})
private Long id;
/**
* 定时器名称
*/
@Column(name = "job_name")
private String jobName;
/**
* Bean名称
*/
@Column(name = "bean_name")
@NotBlank
private String beanName;
/**
* 方法名称
*/
@Column(name = "method_name")
@NotBlank
private String methodName;
/**
* 参数
*/
@Column(name = "params")
private String params;
/**
* cron表达式
*/
@Column(name = "cron_expression")
@NotBlank
private String cronExpression;
/**
* 状态(0、启动;1、不启动)
*/
@Column(name = "is_pause")
private Boolean isPause = false;
/**
* 创建时间
* */
@UpdateTimestamp
@Column(name = "create_date")
private Date createDate;
}
然后建立一个QuartzScheduler来启动注入任务
@Component
public class QuartzScheduler implements ApplicationRunner {
@Autowired
private QuartzDao quartzDao;
@Autowired
private QuartzJobManage quartzJobManage;
@Override
public void run(ApplicationArguments applicationArguments) {
System.out.println("--------------------注入定时任务---------------------");
List<QuartzJob> quartzJobList = quartzDao.getJob();
quartzJobList.forEach(quartzJob -> {
quartzJobManage.buildJob(quartzJob);
});
System.out.println("--------------------定时任务注入完成---------------------");
}
}
QuartzJobManage:
@Slf4j
@Component
public class QuartzJobManage {
private static final String JOB_NAME = "MYJOB_";
@Resource(name = "scheduler")
private Scheduler scheduler;
public void buildJob(QuartzJob quartzJob){
try {
//创建一个jobDetail的实例,将该实例与HelloJob Class绑定
JobDetail jobDetail = JobBuilder.newJob(ExecutionJob.class).withIdentity(JOB_NAME+quartzJob.getId()).build();
//创建一个Trigger触发器的实例,定义该job立即执行
Trigger trigger = TriggerBuilder
.newTrigger()
.withIdentity(JOB_NAME+quartzJob.getId())
.startNow()
.withSchedule(CronScheduleBuilder.cronSchedule(quartzJob.getCronExpression()))
.build();
trigger.getJobDataMap().put(QuartzJob.JOB_KEY, quartzJob);
//重置启动时间
((CronTriggerImpl)trigger).setStartTime(new Date());
//执行定时任务
scheduler.scheduleJob(jobDetail, trigger);
}catch (Exception e){
log.error("创建定时任务失败", e);
}
}
}
CronTrigger格式: [秒] [分] [小时] [日] [月] [周] [年]年可省略
通配符说明:
“"表示所有值. 例如:在分的字段上设置 "”,表示每一分钟都会触发。
“?” 表示不指定值。使用的场景为不需要关心当前设置这个字段的值。例如:要在每月的10号触发一个操作,但不关心是周几,所以需要周位置的那个字段设置为"?" 具体设置为 0 0 0 10* ?
“-” 表示区间。例如 在小时上设置 “10-12”,表示 10,11,12点都会触发。
“,” 表示指定多个值,例如在周字段上设置 “MON,WED,FRI” 表示周一,周三和周五触发
“/“用于递增触发。如在秒上面设置"5/15” 表示从5秒开始,每增15秒触发(5,20,35,50)。 在月字段上设置’1/3’所示每月1号开始,每隔三天触发一次。
“L” 表示最后的意思。在日字段设置上,表示当月的最后一天
“W” 表示离指定日期的最近那个工作日(周一至周五). 例如在日字段上设置"15W”,表示离每月15号最近的那个工作日触发。
ExecutionJob
@Async
public class ExecutionJob extends QuartzJobBean {
private Logger logger = LoggerFactory.getLogger(this.getClass());
private ExecutorService executorService = Executors.newSingleThreadScheduledExecutor();
@Override
public void executeInternal(JobExecutionContext context){
QuartzJob quartzJob = (QuartzJob) context.getMergedJobDataMap().get(QuartzJob.JOB_KEY);
try {
logger.info("任务准备执行,任务名称:{}", quartzJob.getJobName());
QuartzRunnable task = new QuartzRunnable(quartzJob.getBeanName(), quartzJob.getMethodName(),
quartzJob.getParams());
Future<?> future = executorService.submit(task);
future.get();
logger.info("任务执行完毕");
} catch (Exception e) {
logger.error("任务执行失败,任务名称:{}" + quartzJob.getJobName(), e);
}
}
}
在QuartzRunnable里就是将beanname,methodName,param转成要的格式再implements Runnable 的方式跑动这个任务。
说起来quartz的理解和操作方式不难,只是需要将string格式的beanName找到相应的bean再放到JobDetail里,再通过设定CronTrigger再用scheduler来执行就好了,话说还有种SimpleTrigger,有兴趣的可以了解下,lz也只是刚学,写点理解,有不足希望指出。