概述
一、核心概念
Quartz的原理不是很复杂,只要搞明白几个概念,然后知道如何去启动和关闭一个调度程序即可。
1、Job
表示一个工作,要执行的具体内容。此接口中只有一个方法
void execute(JobExecutionContext context)
2、JobDetail
JobDetail表示一个具体的可执行的调度程序,Job是这个可执行程调度程序所要执行的内容,另外JobDetail还包含了这个任务调度的方案和策略。
3、Trigger代表一个调度参数的配置,什么时候去调。
4、Scheduler代表一个调度容器,一个调度容器中可以注册多个JobDetail和Trigger。当Trigger与JobDetail组合,就可以被Scheduler容器调度了。
二、一个最简单入门实例
<!-- 实例化bean -->
<bean id="fileBetDiffScheduleService" class="com.cslo.gm.server.service.FileBetDiffScheduleServiceImpl" />
<!-- 配置MethodInvokingJobDetailFactoryBean -->
<bean id= "winBetDiffScheduleMethod" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
<property name="targetObject" ref="fileBetDiffScheduleService"/>
<property name="targetMethod" value="fileDownload"/>
<property name="concurrent" value="false"/>
</bean>
<!-- 配置定时表达式 -->
<bean id= "winBetDiffScheduleTrigger" class="org.springframework.scheduling.quartz.CronTriggerBean" >
<property name="jobDetail" ref="winBetDiffScheduleMethod" />
<!-- 每一分钟执行一次 -->
<property name="cronExpression" value="0 0 0/1 * * ?" />
</bean>
<!-- 配置调度工厂 -->
<bean id= "testSchedulerFactoryBean"
class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
<property name="triggers" >
<list>
<!-- <ref bean="winScheduleTrigger" />
<ref bean="winNoScheduleTrigger" />
<ref bean="winBetScheduleTrigger" /> -->
</list>
</property>
</bean>
三、透过实例看原理
通过研读Quartz的源代码,和本实例,终于悟出了Quartz的工作原理。
1、scheduler是一个计划调度器容器(总部),容器里面可以盛放众多的JobDetail和trigger,当容器启动后,里面的每个JobDetail都会根据trigger按部就班自动去执行。
2、JobDetail是一个可执行的工作,它本身可能是有状态的。
3、Trigger代表一个调度参数的配置,什么时候去调。
4、当JobDetail和Trigger在scheduler容器上注册后,形成了装配好的作业(JobDetail和Trigger所组成的一对儿),就可以伴随容器启动而调度执行了。
5、scheduler是个容器,容器中有一个线程池,用来并行调度执行每个作业,这样可以提高容器效率。
6、将上述的结构用一个图来表示,如下:
"0 0 12 * * ?" 每天中午12点触发
"0 15 10 ? * *" 每天上午10:15触发
"0 15 10 * * ?" 每天上午10:15触发
"0 15 10 * * ? *" 每天上午10:15触发
"0 15 10 * * ? 2005" 2005年的每天上午10:15触发
"0 * 14 * * ?" 在每天下午2点到下午2:59期间的每1分钟触发
"0 0/5 14 * * ?" 在每天下午2点到下午2:55期间的每5分钟触发
"0 0/5 14,18 * * ?" 在每天下午2点到2:55期间和下午6点到6:55期间的每5分钟触发
"0 0-5 14 * * ?" 在每天下午2点到下午2:05期间的每1分钟触发
"0 10,44 14 ? 3 WED" 每年三月的星期三的下午2:10和2:44触发
"0 15 10 ? * MON-FRI" 周一至周五的上午10:15触发
"0 15 10 15 * ?" 每月15日上午10:15触发
"0 15 10 L * ?" 每月最后一日的上午10:15触发
"0 15 10 ? * 6L" 每月的最后一个星期五上午10:15触发
"0 15 10 ? * 6L 2002-2005" 2002年至2005年的每月的最后一个星期五上午10:15触发
"0 15 10 ? * 6#3" 每月的第三个星期五上午10:15触发
四、总结
1、搞清楚了上Quartz容器执行作业的的原理和过程,以及作业形成的方式,作业注册到容器的方法。就认识明白了Quartz的核心原理。
2、Quartz虽然很庞大,但是一切都围绕这个核心转,为了配置强大时间调度策略,可以研究专门的CronTrigger。要想灵活配置作业和容器属性,可以通过Quartz的properties文件或者XML来实现。
3、要想调度更多的持久化、结构化作业,可以通过数据库读取作业,然后放到容器中执行。
4、所有的一切都围绕这个核心原理转,搞明白这个了,再去研究更高级用法就容易多了。
5、Quartz与Spring的整合也非常简单,Spring提供一组Bean来支持:MethodInvokingJobDetailFactoryBean、SimpleTriggerBean、SchedulerFactoryBean,看看里面需要注入什么属性即可明白了。Spring会在Spring容器启动时候,启动Quartz容器。
6、Quartz容器的关闭方式也很简单,如果是Spring整合,则有两种方法,一种是关闭Spring容器,一种是获取到SchedulerFactoryBean实例,然后调用一个shutdown就搞定了。如果是Quartz独立使用,则直接调用scheduler.shutdown(true);
7、Quartz的JobDetail、Trigger都可以在运行时重新设置,并且在下次调用时候起作用。这就为动态作业的实现提供了依据。你可以将调度时间策略存放到数据库,然后通过数据库数据来设定Trigger,这样就能产生动态的调度。
2、springboot 中使用的定时器
启动类上加注解@EnableScheduling
package com.jinglitong.wallet.job.sendEmail;
import java.util.concurrent.TimeUnit;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import com.jinglitong.wallet.ddbapi.feign.RegOrderSendEmailApi;
import lombok.extern.slf4j.Slf4j;
/**
*
* Copyright (c) 2018, 井立通
* All rights reserved.
* 文件名称: RegOrderSendEmailJob.java
* 作
者: yxl 2018年10月19日
* 创建时间: 2018年10月19日
* 功能说明:统计注册用户数、订单数,发送邮件
*/
@Component
@Slf4j
public class RegOrderSendEmailJob {
@Autowired
private RedisTemplate<String, Object> redisTemplate;
@Value("${countEmail.open}")
private int releaseOpen = 1;
@Autowired
private RegOrderSendEmailApi regOrderSendEmailApi;
public static final String countEamil_Job = "countEamil_job";
@Scheduled(cron = "${countEmail.cron}")
public void send() {
if(releaseOpen == 1)
try {
if (null != redisTemplate.opsForValue().get(countEamil_Job)
&& (int) redisTemplate.opsForValue().get(countEamil_Job) == 1) {
log.error("发送邮件任务再跑着,下次吧!"+redisTemplate.opsForValue().get(countEamil_Job));
} else {
log.info("开始发送统计邮件");
regOrderSendEmailApi.sendEamil();
redisTemplate.opsForValue().set(countEamil_Job, 1, 20, TimeUnit.HOURS);
}
} catch (Exception e) {
log.error("发送邮件错误:" + e.getMessage());
e.printStackTrace();
}finally {
// 删除标识
log.info("结束,删除发送邮件标识:"+countEamil_Job);
redisTemplate.delete(countEamil_Job);
}
}
}
3、SchedulingConfigurer
package com.jinglitong.wallet.job.task.baofenExchangeMEI;
import java.util.Date;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.Trigger;
import org.springframework.scheduling.TriggerContext;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.SchedulingConfigurer;
import org.springframework.scheduling.config.ScheduledTaskRegistrar;
import org.springframework.scheduling.support.CronTrigger;
import org.springframework.stereotype.Component;
import com.jinglitong.wallet.job.service.BaoFenExchangeMEIService;
import com.jinglitong.wallet.job.util.DateUtils;
import lombok.extern.slf4j.Slf4j;
@Component
@Slf4j
@EnableScheduling
public class BaoFenExchangeMEITask implements SchedulingConfigurer {
/**
* 任务开关
*/
@Value("${BaoFenExchangeMEI.open}")
private int baoFenExchangeMEIOpen;
/**
* 任务执行周期
*/
@Value("${BaoFenExchangeMEI.cron}")
private String cron;
@Autowired
private BaoFenExchangeMEIService
baoFenExchangeMEIService;
private static int state = 0;
@Override
public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
// TODO Auto-generated method stub
if(state == 1) {// 如果一个定时任务 在执行
,那么 下一个定时
不能执行
return;
}
Runnable task0 = new Runnable() {
@Override
public void run() {
log.info(DateUtils.getDateTime() + "BaoFenExchangeMEITask satrt,宝分上链转账开始...");
if(baoFenExchangeMEIOpen != 1) {
return;
}
// 定时任务开始执行
等于1
state = 1;
baoFenExchangeMEIService.start();
log.info(DateUtils.getDateTime() + "BaoFenExchangeMEITask end,宝分上链转账结束...");
// 定时任务 执行完等于 0
state = 0;
}
};
Trigger trigger0 = new Trigger() {
@Override
public Date nextExecutionTime(TriggerContext triggerContext) {
// 任务触发.
CronTrigger trigger = new CronTrigger(cron);
Date nextExec = trigger.nextExecutionTime(triggerContext);
return nextExec;
}
};
taskRegistrar.addTriggerTask(task0, trigger0);
}
}
有多个定时任务的时候,调用任务是使用的一个线程,需要并行执行,需要配置线程池
线程池配置:
package com.jinglitong.wallet.job.conf;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.TaskScheduler;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
@Configuration
public class ThreadManager {
@Bean
public TaskScheduler taskScheduler(){
ThreadPoolTaskScheduler taskScheduler = new ThreadPoolTaskScheduler();
taskScheduler.setPoolSize(10);
taskScheduler.initialize();
return taskScheduler;
}
}
最后
以上就是大胆香菇为你收集整理的定时任务使用的全部内容,希望文章能够帮你解决定时任务使用所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复