了解Quartz
Quartz启动器
<!-- quartz启动器 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-quartz</artifactId>
</dependency>
Quartz框架的使用思路
1)job - 任务 - 你要做什么事?
2)Trigger - 触发器 - 你什么时候去做?
3)Scheduler - 任务调度 - 你什么时候需要去做什么事?
Scheduler接口
Scheduler翻译成调度器,Quartz通过调度器来注册、暂停、删除Trigger和JobDetail。Scheduler还拥有一个SchedulerContext,顾名思义就是上下文,通过SchedulerContext我们可以获取到触发器和任务的一些信息。
Trigger接口
Trigger可以翻译成触发器,通过cron表达式或是SimpleScheduleBuilder等类,指定任务执行的周期。系统时间走到触发器指定的时间的时候,触发器就会触发任务的执行。
JobDetail接口
Job接口是真正需要执行的任务。JobDetail接口相当于将Job接口包装了一下,Trigger和Scheduler实际用到的都是JobDetail。
SpringBoot集成Quartz
第一种方式
建表
我选择将定时任务的信息保存在数据库中,优点是显而易见的,定时任务不会因为系统的崩溃而丢失。
建表的sql语句在Quartz的github中可以找到,里面有针对每一种常用数据库的sql语句,具体地址是:Quartz数据库建表sql
配置quartz
spring:
quartz:
# 将任务等保存化到数据库
job-store-type: jdbc
# 程序结束时会等待quartz相关的内容结束
wait-for-jobs-to-complete-on-shutdown: true
# QuartzScheduler启动时更新己存在的Job,这样就不用每次修改targetObject后删除qrtz_job_details表对应记录
overwrite-existing-jobs: true
properties:
org:
quartz:
# scheduler相关
scheduler:
# scheduler的实例名
instanceName: scheduler
instanceId: AUTO
# 持久化相关
jobStore:
class: org.quartz.impl.jdbcjobstore.JobStoreTX
driverDelegateClass: org.quartz.impl.jdbcjobstore.StdJDBCDelegate
# 表示数据库中相关表是QRTZ_开头的
tablePrefix: QRTZ_
useProperties: false
# 线程池相关
threadPool:
class: org.quartz.simpl.SimpleThreadPool
# 线程数
threadCount: 10
# 线程优先级
threadPriority: 5
threadsInheritContextClassLoaderOfInitializingThread: true
datasource:
url: jdbc:mysql://localhost:3306/ysh?useUnicode=true&characterEncoding=utf-8&useSSL=true&serverTimezone=UTC
username: root
password: root
driver-class-name: com.mysql.cj.jdbc.Driver
type: com.alibaba.druid.pool.DruidDataSource
mybatis:
type-aliases-package: com.ysh.pojo
mapper-locations: classpath:dao/*.xml
注册周期性的定时任务
周期性任务一般是固定的,但是一直会执行的任务。
/**
*Quartz的相关配置,注册JobDetail和Trigger
*/
@Configuration
public class QuartzConfig {
@Bean
public JobDetail jobDetail() {
JobDetail jobDetail = JobBuilder.newJob(JobTest.class)
.withIdentity("job_test", "job_test")
.storeDurably()
.build();
return jobDetail;
}
@Bean
public Trigger trigger() {
Trigger trigger = TriggerBuilder.newTrigger()
.forJob(jobDetail())
.withIdentity("job_test", "job_test")
.startNow()
// 每隔两秒执行一次
.withSchedule(CronScheduleBuilder.cronSchedule("0/2 * * * * ?"))
.build();
return trigger;
}
}
可以写一个类来实现Job接口做具体的任务
@Component
public class JobTest extends QuartzJobBean {
@Autowired
UserService userService;
@Override
protected void executeInternal(JobExecutionContext jobExecutionContext)
throws JobExecutionException {
// 任务的具体逻辑
System.out.println("开始了");
userService.addUser();
}
}
解决注入问题
问题:UserService是被spring管理,而JobTest这个Job是Quartz通过反射创建的,即使加了注解@Component,这个StartOfDayJob对象也不会被注册到ioc容器中,更不可能实现依赖的自动装配。
解决:自定义一个JobFactory,继承AdaptableJobFactory,然后重写其中的createJobInstance方法以达到注入的目的
@Component("myAdaptableJobFactory")
public class MyAdaptableJobFactory extends AdaptableJobFactory {
//AutowireCapableBeanFactory 可以将一个对象添加到SpringIOC容器中,并且完成该对象注入
@Autowired
private AutowireCapableBeanFactory autowireCapableBeanFactory;
/**
* 该方法将需要实例化的任务对象手动的添加到springIOC容器中并且完成对象的注入
*/
@Override
protected Object createJobInstance(TriggerFiredBundle bundle) throws Exception {
Object obj = super.createJobInstance(bundle);
//将obj对象添加Spring IOC容器中,并完成注入
this.autowireCapableBeanFactory.autowireBean(obj);
return obj;
}
}
注册无周期性的定时任务
无周期性任务一般是不定时的,一次性的,而且不具有周期性。
- Job类需要获取到一些数据用于任务的执行;
- 任务执行完成后删除Job和Trigger。
代码:暂无。。。
另一种方式
Quartz配置类
/**
* Quartz配置类
*/
@Configuration
public class QuartzConfig {
/**
* 1.创建Job对象
*/
@Bean
public JobDetailFactoryBean jobDetailFactoryBean(){
JobDetailFactoryBean factory = new JobDetailFactoryBean();
//关联我们自己的Job类
factory.setJobClass(MyJob.class);
return factory;
}
/**
* Cron Trigger
*/
@Bean
public CronTriggerFactoryBean cronTriggerFactoryBean(JobDetailFactoryBean
jobDetailFactoryBean){
CronTriggerFactoryBean factory = new CronTriggerFactoryBean();
factory.setJobDetail(jobDetailFactoryBean.getObject());
//设置触发时间
factory.setCronExpression("0/2 * * * * ?");
return factory;
}
/**
* 3.创建Scheduler对象
*/
@Bean
public SchedulerFactoryBean schedulerFactoryBean(CronTriggerFactoryBean
cronTriggerFactoryBean){
SchedulerFactoryBean factory = new SchedulerFactoryBean();
//关联trigger
factory.setTriggers(cronTriggerFactoryBean.getObject());
return factory;
}
}
Job中注入service
public class MyJob implements Job {
@Autowired
private UsersService usersService;
@Override
public void execute(JobExecutionContext arg0) throws JobExecutionException {
System.out.println("Execute...."+new Date());
usersService.addUser();
}
}
解决注入问题
@Component("myAdaptableJobFactory")
public class MyAdaptableJobFactory extends AdaptableJobFactory {
//AutowireCapableBeanFactory 可以将一个对象添加到SpringIOC容器中,并且完成该对象注入
@Autowired
private AutowireCapableBeanFactory autowireCapableBeanFactory;
/**
* 该方法将需要实例化的任务对象手动的添加到springIOC容器中并且完成对象的注入
*/
@Override
protected Object createJobInstance(TriggerFiredBundle bundle) throws Exception {
Object obj = super.createJobInstance(bundle);
//将obj对象添加Spring IOC容器中,并完成注入
this.autowireCapableBeanFactory.autowireBean(obj);
return obj;
}
}
修改QuartzConfig类
/**
* 3.创建Scheduler对象
*/
@Bean
public SchedulerFactoryBean schedulerFactoryBean(CronTriggerFactoryBean
cronTriggerFactoryBean, MyAdaptableJobFactory myAdaptableJobFactory){
SchedulerFactoryBean factory = new SchedulerFactoryBean();
//关联trigger
factory.setTriggers(cronTriggerFactoryBean.getObject());
factory.setJobFactory(myAdaptableJobFactory);
return factory;
}