Quartz - 定时任务框架
一、简介
对于定时任务的调度,设置好出发时间的规则,以及相应的业务处理。
ex:30分钟后 提交订单
二、简单使用
1.引入依赖
<!-- https://mvnrepository.com/artifact/org.quartz-scheduler/quartz -->
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz</artifactId>
<version>2.3.2</version>
</dependency>
2.编写自己的业务类实现Job接口
public class job implements Job {
// 实现Job接口 重写方法
public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
// 方法里实现自己的任务
// 可以通过jobExecutionContext来获取jobDetail的信息
JobDetail jobDetail = jobExecutionContext.getJobDetail();
JobKey key = jobDetail.getKey();
System.out.println(key.getGroup());
System.out.println(key.getName());
System.out.println("Hello Quartz" + new Date());
}
}
3.新建类对定时任务的实现
新建调度器 把配置好的触发器和包装好的任务放到调度器上
public class HelloQuartz {
public static void main(String[] args) throws SchedulerException {
// 1.调度器Scheduler
Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
// 2.设置触发器 主要描述任务的触发时间规则
SimpleTrigger trigger = TriggerBuilder.newTrigger().withIdentity("trigger1", "group1")
.startNow()
.withSchedule(SimpleScheduleBuilder.simpleSchedule().withRepeatCount(10).withIntervalInSeconds(5))
// Calendar日历的一个子类 描述一个时间
.endAt(new GregorianCalendar(2020, 8, 18, 16, 18, 30).getTime())
.build();
// 3.JobDetail 对于我们任务类的包装
JobDetail jobDetail = JobBuilder.newJob(job.class).withIdentity("job1", "group1").build();
// 4.把JobDetail 和 触发器 添加到调度器中
scheduler.scheduleJob(jobDetail,trigger);
// 启动 调度器开始工作
scheduler.start();
}
}
三、核心类说明
Scheduler:调度器,所有的调度都是由他控制,是Quartz的大脑,管理所有的任务。
Job:任务,想定时执行的事情(定义所需的业务逻辑)。
JobDetail:基于Job,进一步的包装,主要是关联所需的Job,并为他指定更加详细的属性(名称、组)。
Trigger:触发器,可以指定给某任务,指定任务的触发机制。
四、Trigger(触发器)
4.1 SimpleTrigger
上述简单使用中已使用过,不做过多的描述。
4.2 CronTrigger(重点)
4.2.1 测试案例
只需要修改触发器 不需要设置起始和结束时间
使用Cron表达式(秒 分 时 日 月 星期几)
*代表每秒 */2代表每两秒 ?代表不限定
public class cronTrigger {
public static void main(String[] args) throws SchedulerException {
// 1.调度器Scheduler
Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
// 2.设置触发器 主要描述任务的触发时间规则
CronTrigger trigger = TriggerBuilder.newTrigger().withIdentity("trigger1", "group1")
.withSchedule(CronScheduleBuilder.cronSchedule("* * * 18 8 ?"))
.build();
// 3.JobDetail 对于我们任务类的包装
JobDetail jobDetail = JobBuilder.newJob(job.class).withIdentity("job1", "group1").build();
// 4.把JobDetail 和 触发器 添加到调度器中
scheduler.scheduleJob(jobDetail,trigger);
// 启动 调度器开始工作
scheduler.start();
}
}
4.2.2 Cron表达式的组成
Cron表达式(秒 分 时 日 月 星期几)
1为周日 2为周一
位置 | 时间域 | 允许值 | 特殊值 |
---|---|---|---|
1 | 秒 | 0-59 | , - * / |
2 | 分 | 0-59 | , - * / |
3 | 时 | 0-23 | , - * / |
4 | 日期 | 1-31 | , - * ? / L W |
5 | 月份 | 1-12 | , - * / |
6 | 星期 | 1-7 | , - * ? / L W # |
7 | 年份 | , - * / |
4.2.3 Cron表达式的符号
*代表每秒 ?代表不限定
2/2代表从2秒开始每两秒 */2代表每两秒
2-10代表从2秒到10秒
2,3,5,7代表指定2秒 3秒 5秒 7秒
L在日期上表示本月最后一天
L放在星期上表示本周的周六,也就是7 6L放在星期上表示本月最后一个周五
10W放在日期上表示离10号最近的一个工作日 不能跨月
LW放在日期上表示本月的最后一个工作日
5#2用在星期上表示本月的第二个周四
五、对于Quartz的整合
5.1 引入依赖
<!--quartz的使用需要依赖于spring的支持-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>5.2.8.RELEASE</version>
</dependency>
<!--quartz的依赖 去掉自带的日志 Springboot中已经有了-->
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz</artifactId>
<version>2.3.2</version>
<exclusions>
<exclusion>
<artifactId>slf4j-api</artifactId>
<groupId>org.slf4j</groupId>
</exclusion>
</exclusions>
</dependency>
<!--spring的事务依赖-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>5.2.6.RELEASE</version>
</dependency>
5.2 编写Job类
也就是自己要实现的业务代码 实现Job接口
public class QuartzDemo implements Job {
@Override
public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
System.out.println("execute()"+new Date());
}
}
5.3 编写Quartz配置类
对JobDetail(做什么) Trigger(什么时间做) Scheduler(什么时间做什么)的配置
@Configuration
public class QuartzConfig {
// 创建Job对象
@Bean
public JobDetailFactoryBean jobDetailFactoryBean(){
JobDetailFactoryBean jobDetailFactoryBean = new JobDetailFactoryBean();
// 关联我们自己的Job类
jobDetailFactoryBean.setJobClass(QuartzDemo.class);
return jobDetailFactoryBean;
}
创建简单Trigger对象
// @Bean
// public SimpleTriggerFactoryBean simpleTriggerFactoryBean(JobDetailFactoryBean jobDetailFactoryBean){
// SimpleTriggerFactoryBean simpleTriggerFactoryBean = new SimpleTriggerFactoryBean();
关联JobDetail对象
// simpleTriggerFactoryBean.setJobDetail(jobDetailFactoryBean.getObject());
该参数为一个执行的毫秒数和次数
// simpleTriggerFactoryBean.setRepeatInterval(2000);
// simpleTriggerFactoryBean.setRepeatCount(10);
// return simpleTriggerFactoryBean;
// }
// 创建CronTrigger对象
@Bean
public CronTriggerFactoryBean cronTriggerFactoryBean(JobDetailFactoryBean jobDetailFactoryBean){
CronTriggerFactoryBean cronTriggerFactoryBean = new CronTriggerFactoryBean();
cronTriggerFactoryBean.setJobDetail(jobDetailFactoryBean.getObject());
cronTriggerFactoryBean.setCronExpression("* * * * * ?");
return cronTriggerFactoryBean;
}
// 创建Scheduler对象
@Bean
public SchedulerFactoryBean schedulerFactoryBean(CronTriggerFactoryBean simpleTriggerFactoryBean){
SchedulerFactoryBean schedulerFactoryBean = new SchedulerFactoryBean();
// 关联Trigger对象
schedulerFactoryBean.setTriggers(simpleTriggerFactoryBean.getObject());
return schedulerFactoryBean;
}
}
5.4 修改启动类
SpringBoot默认不开启定时任务 在启动类上添加@EnableScheduling注解开启
5.5 整合出现的问题
Job类注入其他类时候出现空指针异常
原因:Spring IOC机制要求注入的类和被注入的类都必须在IOC容器中,而Job类的实例化则是在Quartz配置 类中,通过Quartz的AdaptableJobFactory类中的方法利用反射来实现的,所以需要重写此类的方 法,把返回的对象注入到IOC容器中。
@Component("myAdaptableJobFactory")
public class MyAdaptableJobFactory extends AdaptableJobFactory {
// AutowireCapableBeanFactory 用于把对象放入IOC容器
@Autowired
private AutowireCapableBeanFactory autowireCapableBeanFactory;
@Override
public Job newJob(TriggerFiredBundle bundle, Scheduler scheduler) throws SchedulerException {
Job job = super.newJob(bundle, scheduler);
// 把对象放入IOC容器
this.autowireCapableBeanFactory.autowireBean(job);
return job;
}
}
// 创建Scheduler对象
@Bean
public SchedulerFactoryBean schedulerFactoryBean(CronTriggerFactoryBean simpleTriggerFactoryBean,MyAdaptableJobFactory myAdaptableJobFactory){
SchedulerFactoryBean schedulerFactoryBean = new SchedulerFactoryBean();
// 关联Trigger对象
schedulerFactoryBean.setTriggers(simpleTriggerFactoryBean.getObject());
// 添加实例化后的JobFactory
schedulerFactoryBean.setJobFactory(myAdaptableJobFactory);
return schedulerFactoryBean;
}
六、SpringBoot自带的定时任务
Scheduled定时任务器
6.1 引入依赖
使用Spring的依赖
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>5.2.8.RELEASE</version>
</dependency>
6.2 测试案例
@Component
public class ScheduledDemo {
// 定时任务方法
@Scheduled(cron="* * * * * ?")
public void scheduledMethed(){
System.out.println(new Date());
}
}
SpringBoot默认不开启定时任务 在启动类上添加@EnableScheduling注解开启