很多时候我们都需要在程序中使用定时任务,在java中通常会使用Quartz框架来做定时任务,对于Quartz的介绍请参考官网,我这里就不过多介绍。
下面我介绍一下如何在spring boot中使用quartz来做定时任务,该定时任务依赖于JobDetailFactoryBean实现
环境pom.xml
spring boot 2.1.6
因为spring boot官方已经对quartz进行了封装因此只需要引入相应的包即可
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-quartz</artifactId>
</dependency>
代码参考目录
chengjian@gentoo ~/github/spring-quartz $ tree
.
├── pom.xml
├── src
│ ├── main
│ │ ├── java
│ │ │ └── com
│ │ │ └── spring
│ │ │ └── quartz
│ │ │ ├── book
│ │ │ │ ├── entity
│ │ │ │ │ └── Book.java
│ │ │ │ └── service
│ │ │ │ ├── BookService.java
│ │ │ │ └── impl
│ │ │ │ └── BookServiceImpl.java
│ │ │ ├── schedule
│ │ │ │ ├── job
│ │ │ │ │ ├── ScheduleJob1.java
│ │ │ │ │ └── ScheduleJob2.java
│ │ │ │ └── QuartzSchedulerConfig.java
│ │ │ ├── ServletInitializer.java
│ │ │ └── SpringBootQuartzApplication.java
│ │ └── resources
│ │ └── application.properties
│ └── test
│ ├── java
│ │ └── com
│ │ └── spring
│ │ └── quartz
│ │ └── SpringBootQuartzApplicationTests.java
从代码目录看出来核心就是schedule包,里面定义了相应的job和quartz配置
我们定义了一个job接口,这个接口里面就是具体需要定时执行的任务,里面定义了两个类ScheduleJob1和ScheduleJob2表明我们定义了2个需要定时执行的任务。
我们就看第一个类
ScheduleJob1
package com.spring.quartz.schedule.job;
import com.spring.quartz.book.entity.Book;
import com.spring.quartz.book.service.BookService;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.springframework.scheduling.quartz.QuartzJobBean;
public class ScheduleJob1 extends QuartzJobBean {
private BookService bookService;
public void setBookService(BookService bookService) {
this.bookService = bookService;
}
@Override
protected void executeInternal(JobExecutionContext jobExecutionContext) throws JobExecutionException {
try {
System.out.println("------------------任务开始Job1------------------");
Book book = bookService.add();
System.out.println(book.toString());
System.out.println("------------------任务结束Job1------------------");
} catch (Exception e) {
e.printStackTrace();
}
}
}
该类继承自QuartzJobBean,并重写executeInternal方法,这个方法中就是定时任务的核心业务实现,我们所有需要在定时任务中执行都操作都写在executeInternal中。
这里ScheduleJob1并没有通过@Componet之类的注解来实现类的自动实例化同时bookService也没有通过@Autowire之类的方法注入,我们在quartz的配置类中会解决这些问题。
定义好了定时任务的业务实现类我们来看quartz的配置类QuartzSchedulerConfig
package com.spring.quartz.schedule;
import com.spring.quartz.book.service.BookService;
import com.spring.quartz.schedule.job.ScheduleJob1;
import com.spring.quartz.schedule.job.ScheduleJob2;
import org.quartz.CronTrigger;
import org.quartz.JobDataMap;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.quartz.CronTriggerFactoryBean;
import org.springframework.scheduling.quartz.JobDetailFactoryBean;
import org.springframework.scheduling.quartz.SchedulerFactoryBean;
/**
* 定时任务配置
*
* @author chengjian
* @date 2019/5/2
*/
@Configuration
@EnableScheduling
public class QuartzSchedulerConfig {
@Bean(name = "job1DataMap")
public JobDataMap job1DataMap(
@Autowired BookService bookService
) {
JobDataMap jobDataMap = new JobDataMap();
jobDataMap.put("bookService", bookService);
return jobDataMap;
}
@Bean(name = "job2DataMap")
public JobDataMap job2DataMap(
@Autowired BookService bookService
) {
JobDataMap jobDataMap = new JobDataMap();
jobDataMap.put("bookService", bookService);
return jobDataMap;
}
@Bean(name = "job1Factory")
public JobDetailFactoryBean jobDetailFactoryBean1(@Qualifier("job1DataMap") JobDataMap job1DataMap) {
JobDetailFactoryBean jobDetailFactoryBean = new JobDetailFactoryBean();
jobDetailFactoryBean.setJobDataMap(job1DataMap);
jobDetailFactoryBean.setJobClass(ScheduleJob1.class);
jobDetailFactoryBean.setName("job1Factory");
return jobDetailFactoryBean;
}
@Bean(name = "job2Factory")
public JobDetailFactoryBean jobDetailFactoryBean2(@Qualifier("job2DataMap") JobDataMap job2DataMap) {
JobDetailFactoryBean jobDetailFactoryBean = new JobDetailFactoryBean();
jobDetailFactoryBean.setJobDataMap(job2DataMap);
jobDetailFactoryBean.setJobClass(ScheduleJob2.class);
jobDetailFactoryBean.setName("job2Factory");
return jobDetailFactoryBean;
}
@Bean(name = "cronTrigger1")
public CronTriggerFactoryBean cronTriggerFactoryBean1(@Qualifier("job1Factory") JobDetailFactoryBean job1DetailFactoryBean) {
CronTriggerFactoryBean cronTriggerFactoryBean = new CronTriggerFactoryBean();
cronTriggerFactoryBean.setJobDetail(job1DetailFactoryBean.getObject());
cronTriggerFactoryBean.setBeanName("cronTrigger1");
cronTriggerFactoryBean.setStartDelay(1000);
cronTriggerFactoryBean.setCronExpression("10/20 * * * * ? ");
return cronTriggerFactoryBean;
}
@Bean(name = "cronTrigger2")
public CronTriggerFactoryBean cronTriggerFactoryBean2(@Qualifier("job2Factory") JobDetailFactoryBean job1DetailFactoryBean) {
CronTriggerFactoryBean cronTriggerFactoryBean = new CronTriggerFactoryBean();
cronTriggerFactoryBean.setJobDetail(job1DetailFactoryBean.getObject());
cronTriggerFactoryBean.setBeanName("cronTrigger2");
cronTriggerFactoryBean.setStartDelay(3000);
cronTriggerFactoryBean.setCronExpression("10/30 * * * * ? ");
return cronTriggerFactoryBean;
}
@Bean(name = "quartzScheduler")
public SchedulerFactoryBean schedulerFactoryBean1(@Qualifier("cronTrigger1") CronTrigger simpleTriggerFactoryBean, @Qualifier("cronTrigger2") CronTrigger cronTriggerFactoryBean) {
SchedulerFactoryBean schedulerFactoryBean = new SchedulerFactoryBean();
schedulerFactoryBean.setAutoStartup(true);
schedulerFactoryBean.setBeanName("quartzScheduler1");
schedulerFactoryBean.setTriggers(simpleTriggerFactoryBean, cronTriggerFactoryBean);
return schedulerFactoryBean;
}
}
1.JobDataMap是定时任务实现类中定义的一些属性,
@Bean(name = “job1DataMap”)
public JobDataMap job1DataMap(
@Autowired BookService bookService
) {
JobDataMap jobDataMap = new JobDataMap();
jobDataMap.put(“bookService”, bookService);
return jobDataMap;
}
这里我们在ScheduleJob1中定义了bookService这个业务实体对象,我们在jobdatamap中通过put的方式注入到ScheduleJob1
2.JobDetailFactoryBean
@Bean(name = “job1Factory”)
public JobDetailFactoryBean jobDetailFactoryBean1(@Qualifier(“job1DataMap”) JobDataMap job1DataMap) {
JobDetailFactoryBean jobDetailFactoryBean = new JobDetailFactoryBean();
jobDetailFactoryBean.setJobDataMap(job1DataMap);
jobDetailFactoryBean.setJobClass(ScheduleJob1.class);
jobDetailFactoryBean.setName(“job1Factory”);
return jobDetailFactoryBean;
}
这里通过定义JobDetailFactoryBean将ScheduleJob1类实例化为真正的任务实体,并注入通过JobDataMap注入bookService
3.CronTriggerFactoryBean
@Bean(name = “cronTrigger1”)
public CronTriggerFactoryBean cronTriggerFactoryBean1(@Qualifier(“job1Factory”) JobDetailFactoryBean job1DetailFactoryBean) {
CronTriggerFactoryBean cronTriggerFactoryBean = new CronTriggerFactoryBean();
cronTriggerFactoryBean.setJobDetail(job1DetailFactoryBean.getObject());
cronTriggerFactoryBean.setBeanName(“cronTrigger1”);
cronTriggerFactoryBean.setStartDelay(1000);
cronTriggerFactoryBean.setCronExpression("10/20 * * * * ? ");
return cronTriggerFactoryBean;
}
配置好了定时任务实体就需要配置触发器,确定在什么时候触发定时任务执行,触发器的详细配置参数可以参考官网上的,很多详细说法
4.SchedulerFactoryBean
@Bean(name = “quartzScheduler”)
public SchedulerFactoryBean schedulerFactoryBean1(@Qualifier(“cronTrigger1”) CronTrigger simpleTriggerFactoryBean, @Qualifier(“cronTrigger2”) CronTrigger cronTriggerFactoryBean) {
SchedulerFactoryBean schedulerFactoryBean = new SchedulerFactoryBean();
schedulerFactoryBean.setAutoStartup(true);
schedulerFactoryBean.setBeanName(“quartzScheduler1”);
schedulerFactoryBean.setTriggers(simpleTriggerFactoryBean, cronTriggerFactoryBean);
return schedulerFactoryBean;
}
配置好了触发器、定时任务我们就需要把这些元素组装成最终的供系统调用的定时任务体系,所有通过配置SchedulerFactoryBean实现基于JobDetailFactoryBean的定时任务。