1.简介
使用 @Scheduled 注解来解决简单的定时任务,大部分项目中可能都是使用 Quartz 来做定时任务。
Quartz是一个开源项目,专注于任务调度器,功能强大,提供了极为广泛的特性如持久化任务,集群和分布式任务等。 Quartz核心是调度器,还采用多线程管理。
持久化任务:当应用程序停止运行时,所有调度信息不被丢失,当你重新启动时,调度信息还存在,这就是持久化任务。
集群和分布式处理:当在集群环境下,当有配置Quartz的多个客户端(节点)时,
采用Quartz的集群和分布式处理时,简单了解几点
1)一个节点无法完成的任务,会被集群中拥有相同的任务的节点取代执行。
2)Quartz调度是通过触发器的类别来识别不同的任务,在不同的节点定义相同的触发器的类别,这样在集群下能稳定的运行,一个节点无法完成的任务,会被集群中拥有相同的任务的节点取代执行。
3)分布式 体现在 当相同的任务定时在一个时间点,在那个时间点,不会被两个节点同时执行。
2.使用
提前准备:
1.导入依赖 spring-boot-starter-quartz
2.在启动类上添加 @EnableScheduling 注解,表示开启定时任务。
需要定义一个Job(内包括一个jobDetail、trigger),然后把Job加入到调度器(scheduler)中。
2.1 定义 Job
Job 的定义有两种方式:
- 直接定义一个Bean,不支持传参。
@Component
public class MyJob1 {
public void myTask1() {
System.out.println("MyJob1 myTask1任务开始 : " + LocalDateTime.now().toLocalTime() + ",线程:" + Thread.currentThread().getName());
}
}
- 定义一个Bean继承 QuartzJobBean类,并实现默认的方法,支持传参,任务启动时,executeInternal 方法将会被执行。
@Component
public class MyJob2 extends QuartzJobBean {
// @Autowired 这里注入方式是不行的,报NPE
private UserService userService;
private Long id;
@Override
protected void executeInternal(JobExecutionContext jobExecutionContext) throws JobExecutionException {
// 处理相应的注入service业务
String data = userService.get(id);
System.out.println(data);
System.out.println("MyJob2 任务开始 : " + LocalDateTime.now().toLocalTime() + ",线程:" + Thread.currentThread().getName());
}
public UserService getUserService() {
return userService;
}
public void setUserService(UserService userService) {
this.userService = userService;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
}
2.2 定义 JobDetail、Trigger
- JobDetail 的配置有两种方式:
(1)MethodInvokingJobDetailFactoryBean:可以配置目标 Bean 的名字和目标方法的名字,这种方式不支持传参。
(2)JobDetailFactoryBean:任务类继承自 QuartzJobBean ,这种方式支持传参,将参数封装在 JobDataMap 中进行传递。
- Quartz 中定义了多个 Trigger触发器,,这里使用下 SimpleTrigger 和 CronTrigger 。
SimpleTrigger触发器: 有点类似于上面的 @Scheduled 的基本用法。
CronTrigger触发器:支持 cron 表达式来配置任务执行时间
@Configuration
public class QuartzConfig {
// MyJob2 需要 userService, 这两个都可以注入
// @Bean
// UserService userService() {
// return new UserService();
// }
@Autowired
private UserService userService;
// MyJob1任务配置
@Bean
MethodInvokingJobDetailFactoryBean methodInvokingJobDetailFactoryBean() {
MethodInvokingJobDetailFactoryBean bean = new MethodInvokingJobDetailFactoryBean();
bean.setTargetBeanName("myJob1"); // 首字母小写
bean.setTargetMethod("myTask1");
return bean;
}
@Bean
SimpleTriggerFactoryBean simpleTriggerFactoryBean() {
SimpleTriggerFactoryBean bean = new SimpleTriggerFactoryBean();
bean.setStartTime(new Date());
bean.setRepeatCount(5);
bean.setRepeatInterval(2000);
bean.setJobDetail(methodInvokingJobDetailFactoryBean().getObject());
return bean;
}
// MyJob2任务配置
// 传参
@Bean
JobDetailFactoryBean jobDetailFactoryBean() {
JobDetailFactoryBean bean = new JobDetailFactoryBean();
bean.setJobClass(MyJob2.class);
JobDataMap map = new JobDataMap();
map.put("userService", userService);
map.put("id", 101);
bean.setJobDataMap(map);
return bean;
}
@Bean
CronTriggerFactoryBean cronTriggerFactoryBean() {
CronTriggerFactoryBean bean = new CronTriggerFactoryBean();
bean.setCronExpression("0/5 * * * * ?");
bean.setJobDetail(jobDetailFactoryBean().getObject());
return bean;
}
// 添加 MyJob1和MyJob2的触发器
@Bean
SchedulerFactoryBean schedulerFactoryBean() {
SchedulerFactoryBean bean = new SchedulerFactoryBean();
bean.setTriggers(cronTriggerFactoryBean().getObject(), simpleTriggerFactoryBean().getObject());
return bean;
}
}