基于给定的时间点、给定的时间间隔、给定的执行次数自动执行的任务
JDK Timer & TimerTask
Timer的核心是Timer和TimerTask,Timer负责设定TimerTask的起始与间隔执行时间,使用者需要建立一个TimeTask的继承类,实现run方法,然后将其交给Timer使用即可。
import java.util.TimerTask;
/*
* 自定义任务,必须继承TimerTack抽象父类
*/
public class MyTask extends TimerTask{
//实现父类的run()抽象方法
@Override
public void run() {
//......
}
public static void main(String[] args) {
//1.创建任务对象
MyTask myTask = new MyTask();
//2.时间调度器
Timer timer = new Timer();
//Time类中的schedule()方法有四种使用方式:
//方式1:任务task对象,在延迟delay(毫秒)后,自动执行1次
timer.schedule(myTask, delay);
//方式2:调度形式2:任务对象task,在延迟delay(毫秒)后,每隔period(毫秒)执行1次
timer.schedule(myTask, delay, period);
//方式3:任务对象task,在指定时间time,自动执行一次
timer.schedule(myTask, time);
//方式式4:任务对象task,在第一次firstTime执行后,每隔period(毫秒)执行一次
timer.schedule(myTask, firstTime, period);
}
}
在Spring中继承Quartz
Quartz是一个开源的作业调度库,具有丰富的特点,能够与任何Java应用继承。也可以单独运用,也可以应用在大型的商业系统中。Quartz可以创建简单的、复杂的计划,可执行几十,几百甚至 数以万计的作业;作业定义成标准的Java组件,可执行任何需要做的事。Quartz调度程序包括许多企业级特征,如支持JTA事务和聚类。
-
Spring与Quartz的版本兼容问题
Spring 4.x 兼容Quartz 1.8
Spring5.x 兼容 Quartz 1.8 和 2.x - Job:用于封装任务,需要继承QuartzJobBean
- JobDetail:用于封装Job,需将Job注入至JobDetailFactoryBean
- Trigger:触发器,用于封装调度规则逻辑;需将JobDetail注入至SimpleTriggerBean或者CronTriggerBean
- Scheduler :调度器工厂,用于产生调度器,通过调度器按照触发器规则,执行任务;需将Trigger触发器注入至SchedulerFactoryBean调度器工厂。
使用方式
- 导入相关依赖
<!-- Quartz依赖 -->
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz</artifactId>
<version>2.3.2</version>
</dependency>
<!-- Spring集成Quartz,需要添加spring-context-support依赖 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>5.2.1.RELEASE</version>
</dependency>
<!-- Spring集成Quartz,需要添加spring-tx -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>5.2.1.RELEASE</version>
</dependency>
- 通过JobDetail获取注入的属性
public class CodeService {
public String createCode(){
return "SUCCESS";
}
}
import org.quartz.JobDetail;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.springframework.scheduling.quartz.QuartzJobBean;
import java.time.LocalDateTime;
/**
* QuartzJobBean的子类,用于封装任务
*/
public class MyTask extends QuartzJobBean {
//重写executeInternal()方法,用于封装任务实现逻辑
@Override
protected void executeInternal(JobExecutionContext jobExecutionContext) throws JobExecutionException {
//获取当前JobDetail
JobDetail myJobDetail = jobExecutionContext.getJobDetail();
//获取JobDetail中的JobDataMap
MyService myService = (MyService)myJobDetail.getJobDataMap().get("myService");
String code = myService.createCode();
System.out.println("发送提醒短信Message:" + LocalDateTime.now());
System.out.println("短信验证码:" + code);
}
}
- 在xml文件中进行配置
<!-- 自定义任务类 -->
<bean id="myTaskBean" class="com.my.task.MyTask">
<bean id="myServiceBean" class="com.my.service.MyService">
<!-- JobDetail: 任务详情 -->
<!-- 作用:封装Job任务 -->
<!-- 创建:通过JobDetailFactoryBean工厂进行创建 -->
<bean id="messageJobDetail" class="org.springframework.scheduling.quartz.JobDetailFactoryBean">
<!-- 注入Job类的完全限定名(底层通过反射创建该Job对象) -->
<property name="jobClass" ref="myTaskBean"/>
<!-- 通过jobDataAsMap属性,为Job注入值或对象 -->
<property name="myTaskJobDetail">
<map>
<entry key="myService" value-ref="myServiceBean"/>
</map>
</property>
</bean>
<!-- Trigger:触发器 -->
<!-- SimpleTriggerFactoryBean : 一种基于简单时间规则逻辑的触发器工厂 -->
<!-- CronTriggerFactoryBean : 基于cron表达式,可以灵活的表示出更复杂的时间规则的触发器工厂-->
<bean id="myTaskJobTrigger" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">
<!-- 注入时间调度规则(cron表达式) -->
<property name="cronExpression" value="10,13,17,24 * * 6 11 ?"/>
<!-- 注入JobDetail(任务详情) -->
<property name="jobDetail" ref="myTaskJobDetail"/>
</bean>
<!-- 调度器工厂:创建调度器 -->
<bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
<property name="triggers">
<list>
<ref bean="myTaskJobTrigger"/> <!-- 注入Trigger触发器 -->
</list>
</property>
</bean>
- cron表达式组成
秒:0 - 59
分钟:0 - 59
小时:0 -23
日期 :1 -31
月份:0 -11
星期:1 - 7
年份:1970 - 2099
- 字符含义
*:代表所有可能的值
,:表示列出枚举值
?:指“没有具体的值”
-:表示指定范围
/:被用于指定增量
L:单词“last"的缩写,只能用在月份和星期字段中
- cron表达式案例
0 * 14 * * ? 每天下午2点到下午2:59期间的每1分钟触发
0 0 5-15 * * ? 每天5-15点整点触发
0 0/3 * * * ? 没三分钟触发一次
0 0 10,14,16 * * ? 每天上午10点,下午2点、4点
0 0 23 L * ? 每月最后一天23点执行一次
Spring Task
Spring Task是Spring 3.0以后自主开发的定时任务工具,可以将它比作一个轻量级的Quartz,而且使用起来很简单,除Spring相关的包外,不需要额外的包。
- Job任务
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
@Component
public class MyTask {
@Autowired
private CodeService codeService;
@Scheduled(cron = "* * * 6 11 ?")
public void dosth1(){
System.out.println("任务1");
System.out.println("短信验证码:" + codeService.createCode());
}
@Scheduled(cron = "* * * 6 11 ?")
public void dosht2(){
System.out.println("任务2");
System.out.println("短信验证码:" + codeService.createCode());
}
}
- xml配置
<!-- 开启Task注解任务驱动 -->
<task:annotation-driven/>
<!-- 任务对象 -->
<bean id="myTaskBean" class="com.my.job.MyTask"/>
<!-- 调度器池 -->
<task:scheduler id="poolTaskScheduler" pool-size="10"/>
<!-- 调度任务列表:注入调度器池 -->
<!-- 配置指导bean的指定方法,按照cron时间规则执行调度scheduler指定任务线程池 -->
<task:scheduled-tasks scheduler="poolTaskScheduler">
<!-- 任务方法 -->
<task:scheduled ref="myTaskBean" method="dosth1" cron="* * * 6 11 ?"/>
<task:scheduled ref="myTaskBean" method="dosht2" cron="* * * 6 11 ?"/>
</task:scheduled-tasks>
- 设置启动类
import org.springframework.context.annotation.ComponentScan;
import org.springframework.scheduling.annotation.EnableScheduling;
@ComponentScan(basePackages = "com.apesource")
@EnableScheduling
public class AppConfig {
}